From 17ba7744bc07031cf78c25cefdd942892cd6ba21 Mon Sep 17 00:00:00 2001 From: master1lan <278457198@qq.com> Date: Wed, 4 Jan 2023 22:19:58 +0800 Subject: [PATCH] =?UTF-8?q?=E6=90=AD=E5=BB=BAvideo=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E8=8D=89=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 4 +- pnpm-lock.yaml | 213 ++++++++++++++++++++++++- src/components/image/image.module.less | 13 ++ src/components/image/imagetype.ts | 37 +++++ src/components/image/index.tsx | 57 ++----- src/components/image/tool.ts | 1 + src/components/masonry/index.tsx | 17 +- src/components/proview/imageSize.tsx | 34 ++++ src/index.less | 10 -- src/routers/video.tsx | 3 - src/routers/video/index.tsx | 9 ++ src/routers/video/masonry.tsx | 135 ++++++++++++++++ src/routers/video/video.module.less | 77 +++++++++ src/routers/video/videotype.ts | 29 ++++ src/utils/fetch/fetchtype.ts | 13 +- src/utils/index.ts | 53 ++++-- src/utils/time/index.ts | 13 ++ 17 files changed, 642 insertions(+), 76 deletions(-) create mode 100644 src/components/image/imagetype.ts create mode 100644 src/components/proview/imageSize.tsx delete mode 100644 src/routers/video.tsx create mode 100644 src/routers/video/index.tsx create mode 100644 src/routers/video/masonry.tsx create mode 100644 src/routers/video/video.module.less create mode 100644 src/routers/video/videotype.ts diff --git a/package.json b/package.json index ca684a0..dbcec35 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "dependencies": { "@emotion/react": "^11.10.5", "@emotion/styled": "^11.10.5", + "@mui/icons-material": "^5.11.0", "@mui/lab": "5.0.0-alpha.114", "@mui/material": "^5.11.3", "dayjs": "^1.11.7", @@ -22,7 +23,8 @@ "react-dom": "^18.2.0", "react-intersection-observer": "^9.4.1", "react-photo-view": "^1.2.3", - "react-router-dom": "^6.6.1" + "react-router-dom": "^6.6.1", + "react-use": "^17.4.0" }, "devDependencies": { "@babel/core": ">=7.0.0 <8.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 58f3c80..8f718fc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,6 +5,7 @@ specifiers: '@emotion/react': ^11.10.5 '@emotion/styled': ^11.10.5 '@faker-js/faker': ^7.6.0 + '@mui/icons-material': ^5.11.0 '@mui/lab': 5.0.0-alpha.114 '@mui/material': ^5.11.3 '@types/imagesloaded': ^4.1.2 @@ -25,6 +26,7 @@ specifiers: react-intersection-observer: ^9.4.1 react-photo-view: ^1.2.3 react-router-dom: ^6.6.1 + react-use: ^17.4.0 rollup-plugin-visualizer: ^5.9.0 typescript: ^4.9.3 vite: ^4.0.0 @@ -33,6 +35,7 @@ specifiers: dependencies: '@emotion/react': 11.10.5_3grbeiqrb6djg67fiejiqngkdi '@emotion/styled': 11.10.5_pwtpayi7py7ecifctvjbac33ee + '@mui/icons-material': 5.11.0_oiuuhmk4wjjpe4qb2sby7usney '@mui/lab': 5.0.0-alpha.114_k43z3ghfbkgbsmpaivfebys3bq '@mui/material': 5.11.3_lskpmcsdi7ipu6qpuapyu56ihm dayjs: 1.11.7 @@ -46,6 +49,7 @@ dependencies: react-intersection-observer: 9.4.1_react@18.2.0 react-photo-view: 1.2.3_biqbaboplfbrettd7655fr4n2y react-router-dom: 6.6.1_biqbaboplfbrettd7655fr4n2y + react-use: 17.4.0_biqbaboplfbrettd7655fr4n2y devDependencies: '@babel/core': 7.20.7 @@ -679,6 +683,23 @@ packages: resolution: {integrity: sha512-Bgb6//KtxY7IC7M5Pa5RKFX1wttc213mqpKqydnz3wn4BGDXfA5c0vf5nTu5zqsJeB4T3ysAJTRJhQ/E1GsZDQ==} dev: false + /@mui/icons-material/5.11.0_oiuuhmk4wjjpe4qb2sby7usney: + resolution: {integrity: sha512-I2LaOKqO8a0xcLGtIozC9xoXjZAto5G5gh0FYUMAlbsIHNHIjn4Xrw9rvjY20vZonyiGrZNMAlAXYkY6JvhF6A==} + engines: {node: '>=12.0.0'} + peerDependencies: + '@mui/material': ^5.0.0 + '@types/react': ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.20.7 + '@mui/material': 5.11.3_lskpmcsdi7ipu6qpuapyu56ihm + '@types/react': 18.0.26 + react: 18.2.0 + dev: false + /@mui/lab/5.0.0-alpha.114_k43z3ghfbkgbsmpaivfebys3bq: resolution: {integrity: sha512-tChDoLaJ3qcYk37GIwBL1KrCiW0gpmEY//D5z5nHWnO/mzx3axjRJZpBOBeGEvhuoO/Y3QzMz4rhTvqbGNkW0w==} engines: {node: '>=12.0.0'} @@ -1039,6 +1060,10 @@ packages: '@types/sizzle': 2.3.3 dev: true + /@types/js-cookie/2.2.7: + resolution: {integrity: sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA==} + dev: false + /@types/node/18.11.18: resolution: {integrity: sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==} dev: true @@ -1102,6 +1127,10 @@ packages: vite: 4.0.3_dprl76twtlijnqpm3fdjsbkzqm dev: true + /@xobotyi/scrollbar-width/1.9.5: + resolution: {integrity: sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ==} + dev: false + /ansi-regex/5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -1205,6 +1234,12 @@ packages: is-what: 3.14.1 dev: true + /copy-to-clipboard/3.3.3: + resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} + dependencies: + toggle-selection: 1.0.6 + dev: false + /cosmiconfig/7.1.0: resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} engines: {node: '>=10'} @@ -1216,6 +1251,20 @@ packages: yaml: 1.10.2 dev: false + /css-in-js-utils/3.1.0: + resolution: {integrity: sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A==} + dependencies: + hyphenate-style-name: 1.0.4 + dev: false + + /css-tree/1.1.3: + resolution: {integrity: sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==} + engines: {node: '>=8.0.0'} + dependencies: + mdn-data: 2.0.14 + source-map: 0.6.1 + dev: false + /csstype/3.1.1: resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==} @@ -1280,6 +1329,12 @@ packages: is-arrayish: 0.2.1 dev: false + /error-stack-parser/2.1.4: + resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} + dependencies: + stackframe: 1.3.4 + dev: false + /esbuild/0.16.10: resolution: {integrity: sha512-z5dIViHoVnw2l+NCJ3zj5behdXjYvXne9gL18OOivCadXDUhyDkeSvEtLcGVAJW2fNmh33TDUpsi704XYlDodw==} engines: {node: '>=12'} @@ -1327,6 +1382,22 @@ packages: resolution: {integrity: sha512-jQ5Ql18hdCQ4qS+RCrbLfz1n+Pags27q5TwMKvZyhp5hh2UULUYZUy1keqj6k6SYsdqIYjnmz7xyyEY0V67B8Q==} dev: false + /fast-deep-equal/3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + dev: false + + /fast-loops/1.1.3: + resolution: {integrity: sha512-8EZzEP0eKkEEVX+drtd9mtuQ+/QrlfW/5MlwcwK5Nds6EkZ/tRzEexkzUY2mIssnAyVLT+TKHuRXmFNNXYUd6g==} + dev: false + + /fast-shallow-equal/1.0.0: + resolution: {integrity: sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw==} + dev: false + + /fastest-stable-stringify/2.0.2: + resolution: {integrity: sha512-bijHueCGd0LqqNK9b5oCMHc0MluJAx0cwqASgbWMvkO01lCYgIhacVRLcaDz3QnyYIRNJRDwMb41VuT6pHJ91Q==} + dev: false + /find-root/1.1.0: resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} dev: false @@ -1390,6 +1461,10 @@ packages: react-is: 16.13.1 dev: false + /hyphenate-style-name/1.0.4: + resolution: {integrity: sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==} + dev: false + /iconv-lite/0.6.3: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} @@ -1420,6 +1495,13 @@ packages: resolve-from: 4.0.0 dev: false + /inline-style-prefixer/6.0.4: + resolution: {integrity: sha512-FwXmZC2zbeeS7NzGjJ6pAiqRhXR0ugUShSNb6GApMl6da0/XGc4MOJsoWAywia52EEWbXNSy0pzkwz/+Y+swSg==} + dependencies: + css-in-js-utils: 3.1.0 + fast-loops: 1.1.3 + dev: false + /intersection-observer/0.12.2: resolution: {integrity: sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg==} dev: false @@ -1455,6 +1537,10 @@ packages: is-docker: 2.2.1 dev: true + /js-cookie/2.2.1: + resolution: {integrity: sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==} + dev: false + /js-tokens/4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -1547,6 +1633,10 @@ packages: trie-memoize: 1.2.0 dev: false + /mdn-data/2.0.14: + resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==} + dev: false + /mime/1.6.0: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} engines: {node: '>=4'} @@ -1563,6 +1653,24 @@ packages: dev: true optional: true + /nano-css/5.3.5_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-vSB9X12bbNu4ALBu7nigJgRViZ6ja3OU7CeuiV1zMIbXOdmkLahgtPmh3GBOlDxbKY0CitqlPdOReGlBLSp+yg==} + peerDependencies: + react: '*' + react-dom: '*' + dependencies: + css-tree: 1.1.3 + csstype: 3.1.1 + fastest-stable-stringify: 2.0.2 + inline-style-prefixer: 6.0.4 + react: 18.2.0 + react-dom: 18.2.0_react@18.2.0 + rtl-css-js: 1.16.1 + sourcemap-codec: 1.4.8 + stacktrace-js: 2.0.2 + stylis: 4.1.3 + dev: false + /nanoid/3.3.4: resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -1753,6 +1861,40 @@ packages: react-dom: 18.2.0_react@18.2.0 dev: false + /react-universal-interface/0.6.2_react@18.2.0+tslib@2.4.1: + resolution: {integrity: sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw==} + peerDependencies: + react: '*' + tslib: '*' + dependencies: + react: 18.2.0 + tslib: 2.4.1 + dev: false + + /react-use/17.4.0_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-TgbNTCA33Wl7xzIJegn1HndB4qTS9u03QUwyNycUnXaweZkE4Kq2SB+Yoxx8qbshkZGYBDvUXbXWRUmQDcZZ/Q==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@types/js-cookie': 2.2.7 + '@xobotyi/scrollbar-width': 1.9.5 + copy-to-clipboard: 3.3.3 + fast-deep-equal: 3.1.3 + fast-shallow-equal: 1.0.0 + js-cookie: 2.2.1 + nano-css: 5.3.5_biqbaboplfbrettd7655fr4n2y + react: 18.2.0 + react-dom: 18.2.0_react@18.2.0 + react-universal-interface: 0.6.2_react@18.2.0+tslib@2.4.1 + resize-observer-polyfill: 1.5.1 + screenfull: 5.2.0 + set-harmonic-interval: 1.0.1 + throttle-debounce: 3.0.1 + ts-easing: 0.2.0 + tslib: 2.4.1 + dev: false + /react/18.2.0: resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} engines: {node: '>=0.10.0'} @@ -1769,6 +1911,10 @@ packages: engines: {node: '>=0.10.0'} dev: true + /resize-observer-polyfill/1.5.1: + resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==} + dev: false + /resolve-from/4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -1806,6 +1952,12 @@ packages: fsevents: 2.3.2 dev: true + /rtl-css-js/1.16.1: + resolution: {integrity: sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg==} + dependencies: + '@babel/runtime': 7.20.7 + dev: false + /safer-buffer/2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} dev: true @@ -1822,6 +1974,11 @@ packages: loose-envify: 1.4.0 dev: false + /screenfull/5.2.0: + resolution: {integrity: sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==} + engines: {node: '>=0.10.0'} + dev: false + /semver/5.7.1: resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} hasBin: true @@ -1832,11 +1989,21 @@ packages: resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} hasBin: true + /set-harmonic-interval/1.0.1: + resolution: {integrity: sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g==} + engines: {node: '>=6.9'} + dev: false + /source-map-js/1.0.2: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} dev: true + /source-map/0.5.6: + resolution: {integrity: sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA==} + engines: {node: '>=0.10.0'} + dev: false + /source-map/0.5.7: resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} engines: {node: '>=0.10.0'} @@ -1846,14 +2013,42 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} requiresBuild: true - dev: true - optional: true /source-map/0.7.4: resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} engines: {node: '>= 8'} dev: true + /sourcemap-codec/1.4.8: + resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} + deprecated: Please use @jridgewell/sourcemap-codec instead + dev: false + + /stack-generator/2.0.10: + resolution: {integrity: sha512-mwnua/hkqM6pF4k8SnmZ2zfETsRUpWXREfA/goT8SLCV4iOFa4bzOX2nDipWAZFPTjLvQB82f5yaodMVhK0yJQ==} + dependencies: + stackframe: 1.3.4 + dev: false + + /stackframe/1.3.4: + resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} + dev: false + + /stacktrace-gps/3.1.2: + resolution: {integrity: sha512-GcUgbO4Jsqqg6RxfyTHFiPxdPqF+3LFmQhm7MgCuYQOYuWyqxo5pwRPz5d/u6/WYJdEnWfK4r+jGbyD8TSggXQ==} + dependencies: + source-map: 0.5.6 + stackframe: 1.3.4 + dev: false + + /stacktrace-js/2.0.2: + resolution: {integrity: sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg==} + dependencies: + error-stack-parser: 2.1.4 + stack-generator: 2.0.10 + stacktrace-gps: 3.1.2 + dev: false + /string-width/4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -1891,17 +2086,29 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + /throttle-debounce/3.0.1: + resolution: {integrity: sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg==} + engines: {node: '>=10'} + dev: false + /to-fast-properties/2.0.0: resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} engines: {node: '>=4'} + /toggle-selection/1.0.6: + resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==} + dev: false + /trie-memoize/1.2.0: resolution: {integrity: sha512-hEDLVEP1FCgaRtt0oZDJdz2lK9uK7WlB7ASswt9U9cqruSNueVigtRGxI97hevKlViqhAcRgNgzuY/m8FCCMcg==} dev: false + /ts-easing/0.2.0: + resolution: {integrity: sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ==} + dev: false + /tslib/2.4.1: resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==} - dev: true /typescript/4.9.4: resolution: {integrity: sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==} diff --git a/src/components/image/image.module.less b/src/components/image/image.module.less index e69de29..8937228 100644 --- a/src/components/image/image.module.less +++ b/src/components/image/image.module.less @@ -0,0 +1,13 @@ +.imgWrapper { + position: relative; + + &>img { + width: 100%; + display: inline-block; + border-radius: 8px; + outline: 0.5px solid rgba(0, 0, 0, .05); + object-fit: cover; + transition: opacity .5s linear; + -webkit-transition: opacity .5s linear; + } +} \ No newline at end of file diff --git a/src/components/image/imagetype.ts b/src/components/image/imagetype.ts new file mode 100644 index 0000000..92b77e0 --- /dev/null +++ b/src/components/image/imagetype.ts @@ -0,0 +1,37 @@ +/** + * @description Image组件参数 + */ +export type ImageProps = { + /** + * @description 图片的url + * @example "www.example.com/1.jpg" + */ + url: string; + /** + * @description 图片失效的兜底图片url + * @example "www.example.com/fallback.jpg" + * 建议提供base64版本 + */ + fallbackUrl?: string; + /** + * @description 图片默认宽度,因为自适应的原因最终效果可能大于该宽度 + * @default 180 + * @example 180 + */ + width?: number; + /** + * @description 图片高度,注意这个参数只有在已经知道该url对应的图片大小后提供; + * 提供width和该参数后组件依然进行url的请求但不会使用获取的高度和宽度。 + * 注意:组件内将直接使用该参数值!!! + */ + height?: number; + /** + * @description 是否选择监听该组件,设计出来就是为了在出现该图片之后进行网络请求 + * @example true + */ + observer?: boolean; + /** + * @description 在observer为true时,该组件在可视区时执行callback,默认只执行一次。 + */ + callback?: (inView: boolean) => void; +}; diff --git a/src/components/image/index.tsx b/src/components/image/index.tsx index 53ec3e0..17e45f9 100644 --- a/src/components/image/index.tsx +++ b/src/components/image/index.tsx @@ -1,6 +1,8 @@ -import { useCallback, useMemo, useState } from "react"; +import { useCallback, useMemo, useState, memo, ReactElement } from "react"; import { InView } from "react-intersection-observer"; +import { useImageShouldResize } from "@components/proview/imageSize"; import { Once } from "@utils/index"; +import { ImageProps } from "./imagetype"; import styles from "./image.module.less"; import { getImageSize, @@ -9,38 +11,6 @@ import { ImageSize, } from "./tool"; -/** - * @description Image组件参数 - */ -type ImageProps = { - /** - * @description 图片的url - * @example "www.example.com/1.jpg" - */ - url: string; - /** - * @description 图片失效的兜底图片url - * @example "www.example.com/fallback.jpg" - * 建议提供base64版本 - */ - fallbackUrl?: string; - /** - * @description 图片默认宽度,因为自适应的原因最终效果可能大于该宽度 - * @default 180 - * @example 180 - */ - width?: number; - /** - * @description 是否选择监听该组件,设计出来就是为了在出现该图片之后进行网络请求 - * @example true - */ - observer?: boolean; - /** - * @description 在observer为true时,该组件在可视区时执行callback,默认只执行一次。 - */ - callback?: (inView: boolean) => void; -}; - /** * @description 图片预加载hook */ @@ -64,25 +34,31 @@ function useLoading(url: string) { *@description 图片组件库,默认支持图片加载fallback。 */ -export default function Image({ +export default memo(function Image({ url, width = 180, + height, fallbackUrl = DefaultFallbackUrl, observer, callback, -}: ImageProps) { + children, +}: ImageProps & { + children?: ReactElement; +}) { const res = useLoading(url), { isLoaded, success } = res, - real_width = width || 180, + real_width = width, + real_height = height || getResizeHeight(res, real_width), real_fallback_url = fallbackUrl || DefaultFallbackUrl; const once_callback = useCallback(Once(callback!!), []); + const { isShouldchangeSize } = useImageShouldResize(); return ( {({ inView, ref, entry }) => ( -
+
<>{observer && inView && once_callback(inView)} + {children}
)} ); -} +}); diff --git a/src/components/image/tool.ts b/src/components/image/tool.ts index 2aa88c9..727c395 100644 --- a/src/components/image/tool.ts +++ b/src/components/image/tool.ts @@ -50,6 +50,7 @@ export function getImageSize(imageSrc: string): Promise { export function getResizeHeight(imageSizeObj: ImageSize, realwidth: number) { const res = Math.ceil((100 + Math.ceil(Math.random() * 100)) / 5) * 5; if ( + !imageSizeObj || imageSizeObj.success !== true || imageSizeObj.width < 1 || imageSizeObj.height < 1 diff --git a/src/components/masonry/index.tsx b/src/components/masonry/index.tsx index ef95b10..858c5b2 100644 --- a/src/components/masonry/index.tsx +++ b/src/components/masonry/index.tsx @@ -5,6 +5,7 @@ import { FetchNewImages } from "@utils/faker/index"; import { SingleRun, concurrencyRequest } from "@utils/index"; import { fetchVideos } from "@utils/fetch"; import { nanoid } from "nanoid"; +import { getImageSize } from "../image/tool"; export default function Masonry() { const [lists, setLists] = useState([]); const fetchMoreItems = async ( @@ -18,18 +19,18 @@ export default function Masonry() { }), data = res.data.result, urls = data.map((item) => item.face); - await concurrencyRequest(urls, 6, "success", "error"); + const fetchimagres = await concurrencyRequest(urls, getImageSize, 6); setLists((lists) => { return [ ...lists, ...data.map((item, index) => { - if (index !== data.length - 6) { - return { - image: item.face, - name: item.name, - id: nanoid(10), - }; - } + // if (index !== data.length - 6) { + return { + image: item.face, + name: item.name, + id: nanoid(10), + }; + // } return { image: item.face, name: item.name, diff --git a/src/components/proview/imageSize.tsx b/src/components/proview/imageSize.tsx new file mode 100644 index 0000000..8397392 --- /dev/null +++ b/src/components/proview/imageSize.tsx @@ -0,0 +1,34 @@ +import { useContext, useState, createContext, useEffect } from "react"; +import { thorttleFn } from "@utils/index"; +export const image_order_width = 180; + +const ImageContext = createContext<{ isShouldchangeSize: boolean }>({ + isShouldchangeSize: false, +}); + +//todo +//@ts-ignore +const ImageShouldResizeProview = ({ children }) => { + const [isShouldchangeSize, setIs] = useState(false); + useEffect(() => { + const handleWindowResize = () => { + // console.log({ width: window.innerWidth }); + setIs(() => window.innerWidth < image_order_width * 2.5); + }; + handleWindowResize(); + const handlerThrttleResize = thorttleFn(handleWindowResize, 10); + window.addEventListener("resize", handlerThrttleResize); + return () => window.removeEventListener("resize", handlerThrttleResize); + }, []); + return ( + + {children} + + ); +}; + +export const useImageShouldResize = () => { + return useContext(ImageContext); +}; + +export default ImageShouldResizeProview; diff --git a/src/index.less b/src/index.less index 04ab005..71fc882 100644 --- a/src/index.less +++ b/src/index.less @@ -15,16 +15,6 @@ .element-item { min-width: 180px; - img:first-child { - width: 100%; - display: inline-block; - border-radius: 8px; - outline: 0.5px solid rgba(0, 0, 0, .05); - object-fit: cover; - transition: opacity .5s; - -webkit-transition: opacity .5s; - } - .footer { padding: 12px; } diff --git a/src/routers/video.tsx b/src/routers/video.tsx deleted file mode 100644 index 28fe082..0000000 --- a/src/routers/video.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function VideoPage() { - return

这里是video页面

; -} diff --git a/src/routers/video/index.tsx b/src/routers/video/index.tsx new file mode 100644 index 0000000..de59aa0 --- /dev/null +++ b/src/routers/video/index.tsx @@ -0,0 +1,9 @@ +import VideoMasonry from "./masonry"; +export default function VideoPage() { + return ( + <> +

videopage

+ + + ); +} diff --git a/src/routers/video/masonry.tsx b/src/routers/video/masonry.tsx new file mode 100644 index 0000000..11f2dd6 --- /dev/null +++ b/src/routers/video/masonry.tsx @@ -0,0 +1,135 @@ +import Image from "@components/image"; +import { fetchVideos } from "@utils/fetch"; +import { concurrencyRequest } from "@utils/index"; +import { FC, useState, useEffect } from "react"; +import SlowMotionVideoSharpIcon from "@mui/icons-material/SlowMotionVideoSharp"; +import SubjectSharpIcon from "@mui/icons-material/SubjectSharp"; +import Link from "@mui/material/Link"; +import { VideoRouterImageCardType, VideoRouterMasonryType } from "./videotype"; +import { getImageSize, getResizeHeight } from "@components/image/tool"; +import { Masonry as Masonic_masonry } from "masonic"; +import ImageShouldResizeProview from "@components/proview/imageSize"; +import getrealtiveTime, { getVideoTime } from "@utils/time"; +import styles from "./video.module.less"; +/** + * @description 该组件负责渲染视频图片的瀑布流 + */ +export default function VideoMasonry(props: any) { + const [lists, setLists] = useState([]); + const order_width = 180; + useEffect(() => { + // 在内部定义fetchHandler,保证拿到的是同步的 + const fetchHandler = async () => { + const res = await fetchVideos({ + order: "view", + page: 1, + }), + data = res.data.result, + urls = data.map((item) => item.pic); + const imageSizelists = await concurrencyRequest(urls, getImageSize, 6); + setLists((lists) => [ + ...lists, + ...data.map((item, index) => { + const imageSize = imageSizelists[index], + itemRes: VideoRouterImageCardType = { + title: item.title, + bvid: item.bvid, + name: item.name, + tname: item.tname, + copyright: item.copyright, + pic: item.pic, + tag: item.tag, + view: item.view, + coin: item.coin, + share: item.share, + like: item.like, + updated_at: item.updated_at, + danmaku: item.danmaku, + duration: item.duration, + }; + if (imageSize.success === true) { + return { + ...itemRes, + width: order_width, + height: getResizeHeight(imageSize, order_width), + }; + } + return itemRes; + }), + ]); + }; + fetchHandler(); + }, [props]); + return ( +
+ + + +
+ ); +} + +const VideoRouterImageCard: FC<{ data: VideoRouterImageCardType }> = ({ + data: { + pic, + bvid, + name, + tname, + title, + tag, + view, + coin, + share, + like, + updated_at, + danmaku, + duration, + ...res + }, +}) => { + return ( +
+ +
+
+ + + {view} + + + + {danmaku} + +
+ {getVideoTime(duration)} +
+ +
+

+ + {title} + +

+
+ + {name} + {getrealtiveTime(updated_at * 1000)} + +
+
+
+ ); +}; diff --git a/src/routers/video/video.module.less b/src/routers/video/video.module.less new file mode 100644 index 0000000..060f8d1 --- /dev/null +++ b/src/routers/video/video.module.less @@ -0,0 +1,77 @@ +.video-data { + position: absolute; + left: 0; + bottom: 0; + width: 100%; + box-sizing: border-box; + padding: 16px 8px 6px; + border-bottom-left-radius: 8px; + border-bottom-right-radius: 8px; + display: flex; + justify-content: space-between; + align-items: center; + color: #fff; + font-size: 13px; + font-weight: 400; + background-image: linear-gradient(180deg, + rgba(0, 0, 0, 0) 0%, + rgba(0, 0, 0, .8) 100%); + + &-left { + flex: 1; + display: flex; + align-items: center; + + &>span { + font-size: 13px; + display: flex; + align-items: center; + + } + + &>span:not(:last-of-type) { + margin-right: 12px; + } + } +} + +.video-info { + &>p { + color: #18191c; + font-size: 15px; + cursor: pointer; + transition: color .2s linear; + + &:hover, + &:active { + color: #00aeec; + } + + } + + .video-up-info { + a { + font-size: 13px; + color: rgb(148, 153, 160); + cursor: pointer; + transition: color .2s linear; + + &:hover, + &:active { + color: #00aeec; + } + + &>span { + overflow: hidden; + text-overflow: ellipsis; + word-break: break-all; + + &:not(:last-of-type):after { + content: '·'; + margin: 0 4px; + } + + } + } + } +} \ No newline at end of file diff --git a/src/routers/video/videotype.ts b/src/routers/video/videotype.ts new file mode 100644 index 0000000..712300d --- /dev/null +++ b/src/routers/video/videotype.ts @@ -0,0 +1,29 @@ +/** + * 定义video路由的类型 + */ +import { ImageProps } from "@components/image/imagetype"; +import { RFetchVideoRes } from "@utils/fetch/fetchtype"; + +/** + * @description video路由瀑布流卡片参数 + */ +export type VideoRouterImageCardType = Pick< + RFetchVideoRes["data"]["result"][number], + | "bvid" + | "name" + | "tname" + | "copyright" + | "title" + | "pic" + | "tag" + | "view" + | "coin" + | "share" + | "like" + | "updated_at" + | "danmaku" + | "duration" +> & + Omit; + +export type VideoRouterMasonryType = {}; diff --git a/src/utils/fetch/fetchtype.ts b/src/utils/fetch/fetchtype.ts index f97aa30..d42885f 100644 --- a/src/utils/fetch/fetchtype.ts +++ b/src/utils/fetch/fetchtype.ts @@ -115,7 +115,7 @@ interface RFetchVideoResResult { */ pubdate: number; /** - * @description 不知道是啥 + * @description 应该是时长 */ duration: string; /** @@ -124,14 +124,23 @@ interface RFetchVideoResResult { */ view: number; /** - * @description 不知道是啥 + * @description 应该是弹幕数量 * */ danmaku: number; reply: number; favorite: number; + /** + * @description 视频硬币数 + */ coin: number; + /** + * @description 视频分享数 + */ share: number; + /** + * @description 视频点赞数 + */ like: number; score: number; status: number; diff --git a/src/utils/index.ts b/src/utils/index.ts index dc0a096..61f8508 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -39,18 +39,17 @@ export function SingleRun any>(handler: T) { /** * @description 网络请求并发限制函数,默认返回结果队列,如果提供successStatus或者errorStatus则替换resolve和reject结果 */ -export function concurrencyRequest( +export function concurrencyRequest( urls: string[], - maxNum: number = 1, - successStatus?: unknown, - errorStatus?: unknown -): Promise { + requestFn: (url: string) => Promise, + maxNum: number = 1 +): Promise { return new Promise((resolve) => { if (urls.length === 0) { resolve([]); return; } - const results: unknown[] = []; + const results: T[] = []; let index = 0; // 下一个请求的下标 let count = 0; // 当前请求完成的数量 @@ -61,12 +60,12 @@ export function concurrencyRequest( const url = urls[index]; index++; try { - const resp = await fetch(url); + const resp = await requestFn(url); // resp 加入到results - results[i] = successStatus || resp; + results[i] = resp; } catch (err) { // err 加入到results - results[i] = errorStatus || err; + results[i] = err as T; } finally { count++; // 判断是否所有的请求都已完成 @@ -84,3 +83,39 @@ export function concurrencyRequest( } }); } + +export function Pick(originObj: T, ...getAttr: (keyof T)[]) { + let res = {}; + //@ts-ignore + getAttr.forEach((value) => (res[value] = originObj[value])); + return res; +} + +type test = keyof { + a: number; + b: number; +}; + +/** + * 节流函数,指连续触发事件但是在 n 秒中只执行一次函数 + */ + +export function thorttleFn any>( + fn: T, + absTime: number = 3000 +) { + let time: number | Date = 0; + return function (...res: Parameters) { + let curTime = new Date(); + if (time === 0) { + //@ts-ignore + fn.apply(this, res); + time = curTime; + //@ts-ignore + } else if (curTime - time >= absTime) { + time = curTime; + //@ts-ignore + fn.apply(this, res); + } + }; +} diff --git a/src/utils/time/index.ts b/src/utils/time/index.ts index e0cb17d..7b97e96 100644 --- a/src/utils/time/index.ts +++ b/src/utils/time/index.ts @@ -1,9 +1,22 @@ import dayJs from "dayjs"; import realtiveTime from "dayjs/plugin/relativeTime"; +import duration from "dayjs/plugin/duration"; import "dayjs/locale/zh-cn"; dayJs.locale("zh-cn"); dayJs.extend(realtiveTime); +dayJs.extend(duration); export default function getrealtiveTime(time: number): string { return dayJs(time).fromNow(); } + +export function getVideoTime(time: string): string { + const noFormatTime = dayJs + .duration(parseInt(time) * 1000) + .format("DD:HH:mm:ss"); + return noFormatTime + .split(":") + .reduceRight((pre, cur) => + cur === "00" ? (pre.length < 3 ? `${cur}:${pre}` : pre) : `${cur}:${pre}` + ); +}