From e03b2e0750718056721378c4874556d8737af197 Mon Sep 17 00:00:00 2001 From: master1lan <278457198@qq.com> Date: Thu, 5 Jan 2023 21:31:11 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9video=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E7=80=91=E5=B8=83=E5=9B=BE=E7=9A=84=E5=8D=95=E9=A1=B9=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/image/image.module.less | 11 ++- src/index.less | 6 +- src/routers/video/masonry.tsx | 111 ++++++------------------- src/routers/video/masonryItem.tsx | 95 +++++++++++++++++++++ src/utils/index.ts | 56 ++++++++++--- 5 files changed, 179 insertions(+), 100 deletions(-) create mode 100644 src/routers/video/masonryItem.tsx diff --git a/src/components/image/image.module.less b/src/components/image/image.module.less index 8937228..a2a1b3e 100644 --- a/src/components/image/image.module.less +++ b/src/components/image/image.module.less @@ -1,13 +1,20 @@ .imgWrapper { position: relative; + overflow: hidden; + border-radius: 8px; + outline: 0.5px solid rgba(0, 0, 0, .05); &>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; + transition: transform .2s linear; + -webkit-transition: transform .2s linear; + + &:hover { + transform: scale(1.1); + } } } \ No newline at end of file diff --git a/src/index.less b/src/index.less index 71fc882..76b9b23 100644 --- a/src/index.less +++ b/src/index.less @@ -14,9 +14,7 @@ .element-item { min-width: 180px; - - .footer { - padding: 12px; - } + box-sizing: border-box; + padding: 0 5px; } } \ No newline at end of file diff --git a/src/routers/video/masonry.tsx b/src/routers/video/masonry.tsx index 11f2dd6..1454884 100644 --- a/src/routers/video/masonry.tsx +++ b/src/routers/video/masonry.tsx @@ -1,16 +1,15 @@ -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 { concurrencyRequest, Pick } from "@utils/index"; +import { useState, useEffect } from "react"; import { VideoRouterImageCardType, VideoRouterMasonryType } from "./videotype"; -import { getImageSize, getResizeHeight } from "@components/image/tool"; +import { + getImageSize, + getResizeHeight, + ImageSize, +} 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"; +import { VideoRouterImageCard } from "./masonryItem"; /** * @description 该组件负责渲染视频图片的瀑布流 */ @@ -30,23 +29,25 @@ export default function VideoMasonry(props: any) { 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, - }; + const imageSize: ImageSize = imageSizelists[index], + itemRes: VideoRouterImageCardType = Pick( + item, + "title", + "bvid", + "name", + "tname", + "copyright", + "pic", + "tag", + "view", + "coin", + "share", + "like", + "updated_at", + "danmaku", + "duration" + ); + if (imageSize.success === true) { return { ...itemRes, @@ -67,7 +68,6 @@ export default function VideoMasonry(props: any) { items={lists} columnWidth={order_width} rowGutter={10} - columnGutter={10} maxColumnCount={5} render={VideoRouterImageCard} overscanBy={Infinity} @@ -76,60 +76,3 @@ export default function VideoMasonry(props: any) { ); } - -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/masonryItem.tsx b/src/routers/video/masonryItem.tsx new file mode 100644 index 0000000..848c7e5 --- /dev/null +++ b/src/routers/video/masonryItem.tsx @@ -0,0 +1,95 @@ +import Image from "@components/image"; +import { FC } from "react"; +import SlowMotionVideoSharpIcon from "@mui/icons-material/SlowMotionVideoSharp"; +import SubjectSharpIcon from "@mui/icons-material/SubjectSharp"; +import Link from "@mui/material/Link"; +import { VideoRouterImageCardType } from "./videotype"; +import getrealtiveTime, { getVideoTime } from "@utils/time"; +import styles from "./video.module.less"; +import { Omit, Pick } from "@utils/index"; + +export const VideoRouterImageCard: FC<{ data: VideoRouterImageCardType }> = ({ + data, +}) => { + const { pic, bvid } = data; + return ( + + + + {/* todo:lost tag */} + + + + + + ); +}; +const VideoData: FC< + Pick +> = (props) => { + const { view, danmaku, duration } = props; + return ( + + + + + {view} + + + + {danmaku} + + + {getVideoTime(duration)} + + ); +}; +const VideoInfo: FC< + Pick +> = (props) => { + const { title, name, bvid, updated_at } = props; + return ( + + + + {title} + + + + + {name} + {getrealtiveTime(updated_at * 1000)} + + + + ); +}; +// 1-6 todo:写完视频页面展示瀑布图 diff --git a/src/utils/index.ts b/src/utils/index.ts index 61f8508..562f7a6 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -84,22 +84,58 @@ export function concurrencyRequest( }); } -export function Pick(originObj: T, ...getAttr: (keyof T)[]) { - let res = {}; - //@ts-ignore - getAttr.forEach((value) => (res[value] = originObj[value])); - return res; +/** + * @description Pick函数,将对象中的某些属性抽离出来返回一个新对象 + */ +export function Pick( + originObj: T, + ...getAttr: P[] +): Pick { + return getAttr.reduce((pre, cur) => { + pre[cur] = originObj[cur]; + return pre; + }, Object.create(null)); } -type test = keyof { - a: number; - b: number; -}; +/** + * @description Omit函数,将对象中的某些属性剔除返回一个新对象 + */ +export function Omit( + originObj: T, + ...noUseAttr: P[] +): Omit { + return noUseAttr.reduce((pre, cur) => { + delete pre[cur]; + return pre; + }, deepClone(originObj)); +} /** - * 节流函数,指连续触发事件但是在 n 秒中只执行一次函数 + * @description 深拷贝对象 */ +export function deepClone(obj: any, hash = new WeakMap()) { + if (obj === null) return obj; // 如果是null或者undefined我就不进行拷贝操作 + if (obj instanceof Date) return new Date(obj); + if (obj instanceof RegExp) return new RegExp(obj); + // 可能是对象或者普通的值 如果是函数的话是不需要深拷贝 + if (typeof obj !== "object") return obj; + // 是对象的话就要进行深拷贝 + if (hash.get(obj)) return hash.get(obj); + let cloneObj = new obj.constructor(); + // 找到的是所属类原型上的constructor,而原型上的 constructor指向的是当前类本身 + hash.set(obj, cloneObj); + for (let key in obj) { + if (obj.hasOwnProperty(key)) { + // 实现一个递归拷贝 + cloneObj[key] = deepClone(obj[key], hash); + } + } + return cloneObj; +} +/** + * @description 节流函数,指连续触发事件但是在 n 秒中只执行一次函数 + */ export function thorttleFn any>( fn: T, absTime: number = 3000
- - {title} - -
+ + {title} + +