Explorar el Código

优化--图片懒加载组件

shaogen1995 hace 2 años
padre
commit
a2d5d15784

+ 25 - 0
src/App.tsx

@@ -6,10 +6,20 @@ import history from "./utils/history";
 import AuthRoute from "./components/AuthRoute";
 import SpinLoding from "./components/SpinLoding";
 import AsyncSpinLoding from "./components/AsyncSpinLoding";
+import { Image } from "antd";
+import { useDispatch, useSelector } from "react-redux";
+import { RootState } from "./store";
 const Layout = React.lazy(() => import("./pages/Layout"));
 const Login = React.lazy(() => import("./pages/Login"));
 
 export default function App() {
+  const dispatch = useDispatch();
+
+  // 从仓库中获取查看图片的信息
+  const lookBigImg = useSelector(
+    (state: RootState) => state.loginStore.lookBigImg
+  );
+
   return (
     <>
       {/* 关于路由 */}
@@ -24,6 +34,21 @@ export default function App() {
 
       {/* 发送请求的加载组件 */}
       <AsyncSpinLoding />
+
+      {/* 所有图片点击预览查看大图 */}
+      <Image
+        preview={{
+          visible: lookBigImg.show,
+          src: lookBigImg.url,
+          onVisibleChange: (value) => {
+            // 清除仓库信息
+            dispatch({
+              type: "login/lookBigImg",
+              payload: { url: "", show: false },
+            });
+          },
+        }}
+      />
     </>
   );
 }

+ 5 - 0
src/assets/styles/base.css

@@ -138,4 +138,9 @@ img {
 .noFindPage {
   opacity: 0;
   transition: opacity .5s;
+}
+
+/* antd图片预览组件 */
+.ant-image{
+  display: none;
 }

+ 1 - 17
src/components/ImageLazy/index.module.scss

@@ -1,28 +1,12 @@
 .ImageLazy{
   position: relative;
   :global{
-    .showImg{
-      background-color: #fff;
-      position: absolute;
-      top: 0;
-      left: 0;
-      z-index: 99;
-      opacity: 0;
-      pointer-events: none;
-      transition: opacity .3s;
-      width: 100%;
-      height: 100%;
-    }
-    .active{
-      opacity: 1;
-      pointer-events: auto;
-    }
     .lazyBox{
-      cursor: pointer;
       width: 100%;
       height: 100%;
       position: relative;
       .lookImg{
+        cursor: pointer;
         transition: opacity .3s;
         opacity: 0;
         pointer-events: none;

+ 48 - 53
src/components/ImageLazy/index.tsx

@@ -1,12 +1,11 @@
-import React, { useEffect, useRef, useState } from "react";
+import React, { useCallback, useEffect, useState } from "react";
 import styles from "./index.module.scss";
 import Lazyimg from "react-lazyimg-component";
 import { baseURL } from "@/utils/http";
 import imgLoding from "@/assets/img/login/loading.gif";
 import imgErr from "@/assets/img/login/IMGerror.png";
-import classNames from "classnames";
 import { EyeOutlined } from "@ant-design/icons";
-import { Image } from "antd";
+import { useDispatch } from "react-redux";
 
 type Props = {
   width?: number;
@@ -16,74 +15,70 @@ type Props = {
 };
 
 function ImageLazy({ width = 100, height = 100, src, noLook }: Props) {
-  const [defaultUrl, setDefaultUrl] = useState(src ? imgLoding : imgErr);
-  const [defaultShow, setDefaultShow] = useState(true);
+  const dispatch = useDispatch();
 
-  const timeId = useRef(-1);
+  // 图片占位符
+  const [placeholderUrl, setPlaceholderUrl] = useState(
+    src ? imgLoding : imgErr
+  );
+
+  // 默认不能预览图片,加载成功之后能预览
+  const [lookImg, setLookImg] = useState(false);
 
   useEffect(() => {
-    // 组件销毁的时候清理定时器
-    return () => {
-      clearTimeout(timeId.current);
-    };
-  }, []);
+    if (src) {
+      // 进页面查看图片的加载情况
+      // 创建一个img标签
+      const imgDom = document.createElement("img");
+      imgDom.src = baseURL + src;
+
+      // 不管图片加载成功或者失败,都删除掉,提高性能
+      // 图片加载成功
+      imgDom.onload = function () {
+        setLookImg(true);
+        imgDom.remove();
+      };
+      // 图片加载失败
+      imgDom.onerror = function () {
+        setPlaceholderUrl(imgErr);
+        imgDom.remove();
+      };
 
-  const onLoad = (val: any) => {
-    let flag = false;
-    // console.log(val);
-    val.target.onload = function () {
-      setDefaultShow(false);
-      flag = true;
-    };
-    // 5秒后图片还没有加载出来为错误
-    timeId.current = window.setTimeout(() => {
-      if (!flag) setDefaultUrl(imgErr);
-    }, 5000);
-  };
+      return () => {
+        // 离开页面也删掉掉元素
+        imgDom.remove();
+      };
+    }
+  }, [src]);
 
   // 点击预览图片
-  const [visible, setVisible] = useState(false);
+  const lookBigImg = useCallback(() => {
+    dispatch({
+      type: "login/lookBigImg",
+      payload: { url: baseURL + src, show: true },
+    });
+  }, [dispatch, src]);
 
   return (
     <div className={styles.ImageLazy} style={{ width: width, height: height }}>
       <div className="lazyBox">
-        {src ? (
-          <Lazyimg
-            onLoad={onLoad}
-            src={baseURL + src}
-            width={width}
-            height={height}
-            alt=""
-          />
-        ) : null}
+        <Lazyimg
+          src={src ? baseURL + src : ""}
+          width={width}
+          height={height}
+          placeholder={placeholderUrl}
+          alt=""
+        />
 
         {/* 图片预览 */}
-        {noLook ? null : (
-          <div className="lookImg" onClick={() => setVisible(true)}>
+        {noLook || !lookImg ? null : (
+          <div className="lookImg" onClick={lookBigImg}>
             <EyeOutlined />
             &nbsp;
             <div>预览</div>
           </div>
         )}
       </div>
-
-      <img
-        className={classNames("showImg", defaultShow ? "active" : "")}
-        src={defaultUrl}
-        alt=""
-      />
-
-      {/* 预览图片 */}
-      <Image
-        style={{ display: "none" }}
-        preview={{
-          visible,
-          src: baseURL + src,
-          onVisibleChange: (value) => {
-            setVisible(value);
-          },
-        }}
-      />
     </div>
   );
 }

+ 0 - 53
src/components/ImageLazy/index2.tsx

@@ -1,53 +0,0 @@
-// 这个组件没有懒加载和预览效果
-import React, { useState } from "react";
-import { baseURL } from "@/utils/http";
-import imgErr from "@/assets/img/login/IMGerror.png";
-import imgLoding from "@/assets/img/login/loading.gif";
-
-type Props = {
-  width?: number;
-  height?: number;
-  src: string;
-};
-
-function ImageLazy({ width = 100, height = 100, src }: Props) {
-  // 图片地址
-  const [srcLod, setSrcLod] = useState(imgLoding);
-  // 是否第一次加载,如果不使用这个会加载两次
-  const [isFlag, setIsFlag] = useState(false);
-  /**
-   * 图片加载完成
-   */
-  const handleOnLoad = () => {
-    // 判断是否第一次加载
-    if (isFlag) return;
-    // 创建一个img标签
-    const imgDom = new Image();
-    imgDom.src = src;
-    // 图片加载完成使用正常的图片
-    imgDom.onload = function () {
-      setIsFlag(true);
-      setSrcLod(src);
-    };
-    // 图片加载失败使用图片占位符
-    imgDom.onerror = function () {
-      setIsFlag(true);
-      setSrcLod(imgErr);
-    };
-  };
-
-  return (
-    <>
-      <img
-        style={{ width: width, height: height }}
-        src={baseURL + srcLod}
-        onLoad={handleOnLoad}
-        alt=""
-      />
-    </>
-  );
-}
-
-const MemoImageLazy = React.memo(ImageLazy);
-
-export default MemoImageLazy;

+ 11 - 2
src/store/reducer/login.ts

@@ -26,7 +26,12 @@ const initState = {
   // 关于按钮的权限信息
   authButtonArr: [],
   // 外层页面的权限信息
-  authPageArr:[]
+  authPageArr: [],
+  // 所有图片点击预览查看大图
+  lookBigImg: {
+    url:'',
+    show:false
+  },
 };
 
 type LoginActionType =
@@ -34,7 +39,8 @@ type LoginActionType =
   | { type: "login/setFileData"; payload: any }
   | { type: "login/setGoodsSonList"; payload: any }
   | { type: "login/setAuthButtonArr"; payload: any }
-  | { type: "login/setAuthPageArr"; payload: any };
+  | { type: "login/setAuthPageArr"; payload: any }
+  | { type: "login/lookBigImg"; payload: any };
 // 频道 reducer
 export default function loginReducer(
   state = initState,
@@ -56,6 +62,9 @@ export default function loginReducer(
     // 关于外层页面的权限信息
     case "login/setAuthPageArr":
       return { ...state, authPageArr: action.payload };
+    // 所有图片点击预览查看大图
+    case "login/lookBigImg":
+      return { ...state, lookBigImg: action.payload };
     default:
       return state;
   }