Browse Source

图片懒加载和预览组件封装

shaogen1995 2 years ago
parent
commit
43c21989db

+ 30 - 0
package-lock.json

@@ -22,6 +22,7 @@
         "js-base64": "^3.7.3",
         "react": "^18.2.0",
         "react-dom": "^18.2.0",
+        "react-lazyimg-component": "^1.0.1",
         "react-redux": "^8.0.4",
         "react-router-dom": "5.3",
         "react-scripts": "5.0.1",
@@ -8535,6 +8536,11 @@
         "node": ">= 0.4"
       }
     },
+    "node_modules/intersection-observer": {
+      "version": "0.12.2",
+      "resolved": "https://registry.npmmirror.com/intersection-observer/-/intersection-observer-0.12.2.tgz",
+      "integrity": "sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg=="
+    },
     "node_modules/ipaddr.js": {
       "version": "2.0.1",
       "resolved": "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz",
@@ -14030,6 +14036,17 @@
       "resolved": "https://registry.npmmirror.com/react-is/-/react-is-17.0.2.tgz",
       "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
     },
+    "node_modules/react-lazyimg-component": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmmirror.com/react-lazyimg-component/-/react-lazyimg-component-1.0.1.tgz",
+      "integrity": "sha512-E3RqqLa4m1OO+L5jsiVo8Z8iFH4AkQn+MiZwb3T1J+5yqhd67cnlmjMYgMfa1B63bVecRAI6KNQO9uCVWgU6cg==",
+      "dependencies": {
+        "intersection-observer": "^0.12.0"
+      },
+      "peerDependencies": {
+        "react": ">=16.8.0"
+      }
+    },
     "node_modules/react-redux": {
       "version": "8.0.4",
       "resolved": "https://registry.npmmirror.com/react-redux/-/react-redux-8.0.4.tgz",
@@ -23395,6 +23412,11 @@
         "side-channel": "^1.0.4"
       }
     },
+    "intersection-observer": {
+      "version": "0.12.2",
+      "resolved": "https://registry.npmmirror.com/intersection-observer/-/intersection-observer-0.12.2.tgz",
+      "integrity": "sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg=="
+    },
     "ipaddr.js": {
       "version": "2.0.1",
       "resolved": "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz",
@@ -27446,6 +27468,14 @@
       "resolved": "https://registry.npmmirror.com/react-is/-/react-is-17.0.2.tgz",
       "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
     },
+    "react-lazyimg-component": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmmirror.com/react-lazyimg-component/-/react-lazyimg-component-1.0.1.tgz",
+      "integrity": "sha512-E3RqqLa4m1OO+L5jsiVo8Z8iFH4AkQn+MiZwb3T1J+5yqhd67cnlmjMYgMfa1B63bVecRAI6KNQO9uCVWgU6cg==",
+      "requires": {
+        "intersection-observer": "^0.12.0"
+      }
+    },
     "react-redux": {
       "version": "8.0.4",
       "resolved": "https://registry.npmmirror.com/react-redux/-/react-redux-8.0.4.tgz",

+ 1 - 0
package.json

@@ -17,6 +17,7 @@
     "js-base64": "^3.7.3",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
+    "react-lazyimg-component": "^1.0.1",
     "react-redux": "^8.0.4",
     "react-router-dom": "5.3",
     "react-scripts": "5.0.1",

BIN
src/assets/img/login/IMGerror.png


BIN
src/assets/img/login/imgErr.png


BIN
src/assets/img/login/loading.gif


+ 2 - 1
src/assets/styles/base.css

@@ -123,4 +123,5 @@ textarea{
 
 img{
   object-fit: cover;
-}
+}
+

+ 51 - 0
src/components/ImageLazy/index.module.scss

@@ -0,0 +1,51 @@
+.ImageLazy{
+  position: relative;
+  :global{
+    .showImg{
+      background-color: #fff;
+      position: absolute;
+      top: 0;
+      left: 0;
+      z-index: 99;
+      opacity: 0;
+      pointer-events: none;
+      width: 100%;
+      height: 100%;
+    }
+    .active{
+      opacity: 1;
+      pointer-events: auto;
+    }
+    .lazyBox{
+      cursor: pointer;
+      width: 100%;
+      height: 100%;
+      position: relative;
+      .lookImg{
+        opacity: 0;
+        pointer-events: none;
+        position: absolute;
+        top: 0;
+        left: 0;
+        width: 100%;
+        height: 100%;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        font-size: 18px;
+        color: #fff;
+        background-color: rgba(0,0,0,.6);
+        &>div{
+          font-size: 14px;
+        }
+      }
+      &:hover{
+        .lookImg{
+          opacity: 1;
+          pointer-events: auto;
+        }
+      }
+    }
+  }
+
+}

+ 78 - 0
src/components/ImageLazy/index.tsx

@@ -0,0 +1,78 @@
+import React, { 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';
+
+type Props = {
+  width?: number;
+  height?: number;
+  src: string;
+};
+
+function ImageLazy({ width = 100, height = 100, src }: Props) {
+  const [defaultUrl, setDefaultUrl] = useState(imgLoding);
+  const [defaultShow, setDefaultShow] = useState(true);
+
+  const onLoad = (val: any) => {
+    let flag = false;
+    // console.log(val);
+    val.target.onload = function () {
+      setDefaultShow(false);
+      flag = true;
+    };
+    // 5秒后图片还没有加载出来为错误
+    window.setTimeout(() => {
+      if (!flag) setDefaultUrl(imgErr);
+    }, 5000);
+  };
+
+  // 点击预览图片
+  const [visible, setVisible] = useState(false);
+
+  return (
+    <div className={styles.ImageLazy} style={{ width: width, height: height }}>
+      <div className="lazyBox">
+        <Lazyimg
+          onLoad={onLoad}
+          src={baseURL + src}
+          width={width}
+          height={height}
+          alt=""
+        />
+        {/* 图片预览 */}
+        <div className="lookImg" onClick={() => setVisible(true)}>
+          <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>
+  );
+}
+
+const MemoImageLazy = React.memo(ImageLazy);
+
+export default MemoImageLazy;

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

@@ -0,0 +1,54 @@
+import React, { useState } from "react";
+import styles from "./index.module.scss";
+import Lazyimg from "react-lazyimg-component";
+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;

+ 31 - 0
src/components/ObjectAdd/index.css

@@ -0,0 +1,31 @@
+/* 添加新藏品的弹出框 */
+.ObjectAdd .ObjectAddTit {
+  border-top: 1px solid #999999;
+  padding-top: 15px;
+  width: 100%;
+  height: 45px;
+  display: flex;
+  margin-bottom: 15px;
+}
+.ObjectAdd .ObjectAddTit > div {
+  cursor: pointer;
+  width: 50%;
+  height: 30px;
+  border: 1px solid #999999;
+  text-align: center;
+  line-height: 28px;
+  border-radius: 5px 0 0 5px;
+}
+.ObjectAdd .ObjectAddTit .ObjectAddTitTow {
+  border-radius: 0 5px 5px 0;
+}
+.ObjectAdd .ObjectAddTit .active {
+  background-color: var(--themeColor);
+  color: #fff;
+}
+.ObjectAdd .ant-modal-close {
+  display: none;
+}
+.ObjectAdd .ant-modal {
+  width: 1200px !important;
+}

+ 36 - 0
src/components/ObjectAdd/index.less

@@ -0,0 +1,36 @@
+/* 添加新藏品的弹出框 */
+.ObjectAdd {
+  
+  .ObjectAddTit{
+    border-top: 1px solid #999999;
+    padding-top: 15px;
+    width: 100%;
+    height: 45px;
+    display: flex;
+    margin-bottom: 15px;
+    &>div{
+      cursor: pointer;
+      width: 50%;
+      height: 30px;
+      border: 1px solid #999999;
+      text-align: center;
+      line-height: 28px;
+      border-radius: 5px 0 0 5px;
+    }
+    .ObjectAddTitTow{
+      border-radius: 0 5px 5px 0;
+    }
+    .active{
+      background-color: var(--themeColor);
+      color: #fff;
+    }
+  }
+
+  .ant-modal-close {
+    display: none;
+  }
+
+  .ant-modal {
+    width: 1200px !important;
+  }
+}

+ 9 - 0
src/components/ObjectAdd/index.module.scss

@@ -0,0 +1,9 @@
+.ObjectAdd{
+  position: fixed;
+  z-index: 10;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background-color: rgba(255,255,255,.6);
+}

+ 86 - 0
src/components/ObjectAdd/index.tsx

@@ -0,0 +1,86 @@
+import { Button, Form, Input, message, Modal } from "antd";
+import React, { useState } from "react";
+import styles from "./index.module.scss";
+import classNames from "classnames";
+import "./index.css";
+
+type Props = {
+  id: any;
+  colsePage: any;
+};
+
+function ObjectAdd({ id, colsePage }: Props) {
+  // 没有通过校验
+  const onFinishFailed = () => {
+    return message.warning("有表单不符号规则!");
+  };
+  // 通过校验之后发送请求
+  const onFinish = async (values: any) => {
+    console.log("--点击确定存到仓库", values);
+  };
+
+  // 选择商品信息还是附近(默认商品信息)
+  const [titSelect, setTitSelect] = useState("tit1");
+
+  return (
+    <div className={styles.ObjectAdd}>
+      <Modal
+        wrapClassName="ObjectAdd"
+        destroyOnClose
+        open={true}
+        title={id ? "编辑藏品" : "添加藏品"}
+        footer={
+          [] // 设置footer为空,去掉 取消 确定默认按钮
+        }
+      >
+        {/* 商品信息和附件切换 */}
+        <div className="ObjectAddTit">
+          <div
+            onClick={() => setTitSelect("tit1")}
+            className={classNames(titSelect === "tit1" ? "active" : "")}
+          >
+            商品信息
+          </div>
+          <div
+            onClick={() => setTitSelect("tit2")}
+            className={classNames(
+              "ObjectAddTitTow",
+              titSelect === "tit2" ? "active" : ""
+            )}
+          >
+            附件
+          </div>
+        </div>
+
+        <Form
+          name="basic"
+          labelCol={{ span: 5 }}
+          wrapperCol={{ span: 16 }}
+          onFinish={onFinish}
+          onFinishFailed={onFinishFailed}
+          autoComplete="off"
+        >
+          <Form.Item
+            label="旧密码"
+            name="oldPassword"
+            rules={[{ required: true, message: "不能为空!" }]}
+          >
+            <Input maxLength={15} />
+          </Form.Item>
+
+          <Form.Item wrapperCol={{ offset: 14, span: 16 }}>
+            <Button onClick={colsePage}>取消</Button>
+            &emsp;
+            <Button type="primary" htmlType="submit">
+              确定
+            </Button>
+          </Form.Item>
+        </Form>
+      </Modal>
+    </div>
+  );
+}
+
+const MemoObjectAdd = React.memo(ObjectAdd);
+
+export default MemoObjectAdd;

+ 70 - 35
src/pages/ObjectSon/Object1/AddObject1/index.tsx

@@ -1,12 +1,14 @@
 import AuthButton from "@/components/AuthButton";
 import BreadTit from "@/components/BreadTit";
 import history, { urlParameter } from "@/utils/history";
-import { Input, message, Select, Image, Table, Popconfirm } from "antd";
+import { Input, message, Select, Table, Popconfirm, Image } from "antd";
 import TextArea from "antd/es/input/TextArea";
-import React, { useEffect, useMemo, useState } from "react";
+import React, { useEffect, useMemo, useRef, useState } from "react";
 import { useLocation } from "react-router-dom";
-import imgErr from "@/assets/img/login/imgErr.png";
+import imgErr from "@/assets/img/login/IMGerror.png";
 import styles from "./index.module.scss";
+import ObjectAdd from "@/components/ObjectAdd";
+import ImageLazy from "@/components/ImageLazy/index";
 function AddObject1() {
   // 获取地址栏参数
   const location = useLocation();
@@ -45,7 +47,11 @@ function AddObject1() {
 
   // 点击删除
   const delTableListFu = () => {
-    console.log("删除");
+    console.log("多个删除", tableSelectList);
+  };
+
+  const delOne = (id: number) => {
+    console.log("单个删除", id);
   };
 
   const rowSelection = {
@@ -54,27 +60,33 @@ function AddObject1() {
     },
   };
 
-  const [results, setResults] = useState([
-    {
-      id: 1,
-      name: "图片1",
-      img: "https://ts1.cn.mm.bing.net/th/id/R-C.6d2d3fecd79a96e43d1a410640d7199b?rik=B7RCgF82Vb7P0A&riu=http%3a%2f%2f5b0988e595225.cdn.sohucs.com%2fimages%2f20190831%2f3e03e9c2473c40b180aa99a37c0589fa.jpeg&ehk=JXdgMrjnolHlMkdX9N0K7%2fzBc9wi7FSFDjSGclreQbI%3d&risl=&pid=ImgRaw&r=0",
-    },
-    { id: 2, name: "图片2", img: "" },
-    { id: 3, name: "图片3", img: "" },
-    { id: 4, name: "图片4", img: "" },
-    { id: 5, name: "图片4", img: "" },
-    { id: 6, name: "图片4", img: "" },
-    { id: 7, name: "图片4", img: "" },
-    { id: 8, name: "图片4", img: "" },
-    { id: 9, name: "图片4", img: "" },
-    { id: 10, name: "图片4", img: "" },
-    {
-      id: 11,
-      name: "图片4",
-      img: "https://ts1.cn.mm.bing.net/th/id/R-C.3745122e5760fe2283195293d76bc1e0?rik=YBMOcCcn7CX6Ig&riu=http%3a%2f%2fup.deskcity.org%2fpic%2f20%2fe4%2f4d%2f20e44dce0fe116832ba890edaf2ede32.jpg&ehk=vldj1pqTKyKgirU8ck%2f%2bJWEhtPm22Owe5VEmGNMeLpA%3d&risl=&pid=ImgRaw&r=0",
-    },
-  ]);
+  const results = useMemo(() => {
+    return [
+      {
+        id: 1,
+        name: "图片1",
+        img: "https://ts1.cn.mm.bing.net/th/id/R-C.6d2d3fecd79a96e43d1a410640d7199b?rik=B7RCgF82Vb7P0A&riu=http%3a%2f%2f5b0988e595225.cdn.sohucs.com%2fimages%2f20190831%2f3e03e9c2473c40b180aa99a37c0589fa.jpeg&ehk=JXdgMrjnolHlMkdX9N0K7%2fzBc9wi7FSFDjSGclreQbI%3d&risl=&pid=ImgRaw&r=0",
+      },
+      { id: 2, name: "图片2", img: "https://ts1.cn.mm" },
+      {
+        id: 3,
+        name: "图片3",
+        img: "http://project.4dage.com:8016/content/1_1001/img/20220810_1553241331042.JPG",
+      },
+      { id: 4, name: "图片4", img: "3" },
+      { id: 5, name: "图片4", img: "4" },
+      { id: 6, name: "图片4", img: "5" },
+      { id: 7, name: "图片4", img: "6" },
+      { id: 8, name: "图片4", img: "7" },
+      { id: 9, name: "图片4", img: "8" },
+      { id: 10, name: "图片4", img: "9" },
+      {
+        id: 11,
+        name: "图片4",
+        img: "https://ts1.cn.mm.bing.net/th/id/R-C.3745122e5760fe2283195293d76bc1e0?rik=YBMOcCcn7CX6Ig&riu=http%3a%2f%2fup.deskcity.org%2fpic%2f20%2fe4%2f4d%2f20e44dce0fe116832ba890edaf2ede32.jpg&ehk=vldj1pqTKyKgirU8ck%2f%2bJWEhtPm22Owe5VEmGNMeLpA%3d&risl=&pid=ImgRaw&r=0",
+      },
+    ];
+  }, []);
 
   const columns = useMemo(() => {
     return [
@@ -82,13 +94,13 @@ function AddObject1() {
         title: "缩略图",
         render: (item: any) => (
           <div className="tableImg">
-            <Image
+            <ImageLazy width={120} height={70} src={item.img} />
+            {/* <Image
+              src={item.img}
               width={120}
               height={70}
               placeholder={true}
-              fallback={imgErr}
-              src={item.img}
-            />
+            /> */}
           </div>
         ),
       },
@@ -100,17 +112,23 @@ function AddObject1() {
         title: "操作",
         render: (item: any) => (
           <>
-            <AuthButton type="text" danger>
+            <AuthButton type="text" danger onClick={() => addPageFu(item.id)}>
               编辑
             </AuthButton>
-            <AuthButton type="text" danger>
-              删除
-            </AuthButton>
+            <Popconfirm
+              title="确定删除吗?"
+              okText="确定"
+              cancelText="取消"
+              onConfirm={() => delOne(item.id)}
+            >
+              <AuthButton type="text" danger>
+                删除
+              </AuthButton>
+            </Popconfirm>
           </>
         ),
       },
     ];
-    // eslint-disable-next-line react-hooks/exhaustive-deps
   }, []);
 
   // 点击返回
@@ -128,6 +146,18 @@ function AddObject1() {
     // cancelFu()
   };
 
+  // 点击添加或者编辑出来页面
+  const [addPage, setAddPage] = useState(false);
+
+  // 点击添加或者编辑
+
+  const addId = useRef<any>(null);
+
+  const addPageFu = (id?: any) => {
+    addId.current = id;
+    setAddPage(true);
+  };
+
   return (
     <div className={styles.AddObject1}>
       <div className="breadTit">
@@ -188,7 +218,8 @@ function AddObject1() {
           <div className="addTableBox_Tit">
             <div className="addTableBox_TitL">藏品信息</div>
             <div className="addTableBox_TitR">
-              <AuthButton>添加</AuthButton>&emsp;
+              <AuthButton onClick={() => addPageFu(null)}>添加</AuthButton>
+              &emsp;
               <Popconfirm
                 title="确定删除吗?"
                 okText="确定"
@@ -224,6 +255,10 @@ function AddObject1() {
           </div>
         </div>
       </div>
+      {/* 点击添加或者编辑出来的页面 */}
+      {addPage ? (
+        <ObjectAdd id={addId.current} colsePage={() => setAddPage(false)} />
+      ) : null}
     </div>
   );
 }

+ 9 - 1
src/pages/ObjectSon/Object1/index.tsx

@@ -55,8 +55,16 @@ export default function Object1() {
     pageNumRef.current = tableSelect.pageNum;
   }, [tableSelect.pageNum]);
 
+  // 防止返回的时候发送了2次请求来对应页码
+
+  const getListRef = useRef(-1);
+
   useEffect(() => {
-    getList();
+    clearTimeout(getListRef.current);
+    getListRef.current = window.setTimeout(() => {
+      getList();
+    }, 100);
+
     // eslint-disable-next-line react-hooks/exhaustive-deps
   }, [tableSelect]);
 

+ 3 - 1
src/types/declaration.d.ts

@@ -1,4 +1,6 @@
 declare module 'history'
 declare module '*.scss';
 declare module '*.png';
-declare module 'moment';
+declare module '*.gif';
+declare module 'moment';
+declare module 'react-lazy-load-image-component'

+ 1 - 1
src/utils/http.ts

@@ -4,7 +4,7 @@ import { getTokenInfo, removeTokenInfo } from "./storage";
 import { message } from "antd";
 // 请求基地址
 export const baseURL =
-  process.env.NODE_ENV === "development" ? "https://hnbwg.4dage.com" : "";
+  process.env.NODE_ENV === "development" ? "" : "";
 
 // 创建 axios 实例
 const http = axios.create({