使用技术
- 使用 next.js 的 image 组件显示图片。自带图片压缩生成快速预览的 webp 格式图片
- 使用 antd 的 previewgroup 组件实现原图浏览,自带缩小、放大、上一张、下一张等功能
功能实现
文件树
explorer/src/app/path/[[...path]]/card-display.tsx
explorer/src/app/path/[[...path]]/page.tsx
explorer/src/components/preview/ext-rxp.tsx
explorer/src/components/preview/index.tsx
explorer/src/components/preview/proview-group-context.tsx
explorer/src/components/use-replace-pathname.ts
文件路径:explorer/src/components/preview/ext-rxp.tsx
一些判断文件后缀名方法
export const imgrxp = /\.(jpg|jpeg|gif|png|webp|ico)$/i const rawrxp = /\.(cr2|arw)/i const gifrxp = /\.(gif)$/i const ziprxp = /\.(zip|rar|7z|tar\.xz|tar)(\.+\d+)?$/i const videorxp = /\.(mp4|mkv|mov|wmv|avi|avchd|flv|f4v|swf)(\.+\d+)?$/i export const israw = (path: string) => rawrxp.test(path) export const isimage = (path: string) => imgrxp.test(path) export const isgif = (path: string) => gifrxp.test(path) export const iszip = (path: string) => ziprxp.test(path) export const isvideo = (path: string) => videorxp.test(path)
文件路径:explorer/src/components/preview/index.tsx
预览封装组件,根据是否为文件夹、视频、图片、压缩包显示不同的 icon。
点击图片时,使用 antd 的 previewgroup 组件查看原图。
import react from 'react' import { fileoutlined, filezipoutlined, folderoutlined, videocameraoutlined } from '@ant-design/icons' import image from 'next/image' import { isgif, isimage, isvideo, iszip } from '@/components/preview/ext-rxp' import { usepreviewgroupdispatch } from '@/components/preview/proview-group-context' import { readdiritemtype } from '@/explorer-manager/src/type' import { usereplacepathname } from '@/components/use-replace-pathname' const preview: react.fc<{ item: readdiritemtype }> = ({ item }) => { const previewgroupdispatch = usepreviewgroupdispatch() const { name, is_directory } = item const { staticpath, joinsearchpath } = usereplacepathname() if (is_directory) { return <folderoutlined /> } if (isvideo(name)) { return <videocameraoutlined /> } if (isimage(name)) { const image_path = staticpath(name) return ( <image onclick={() => previewgroupdispatch(name)} src={image_path} alt={name} fill sizes="375px" style={{ objectfit: 'scale-down', //"contain" | "cover" | "fill" | "none" | "scale-down" }} unoptimized={isgif(image_path)} placeholder="empty" /> ) } if (iszip(name)) { return <filezipoutlined /> } return <fileoutlined /> } export default preview
文件路径:explorer/src/components/preview/proview-group-context.tsx
antd previewgroup 组件封装。
需要在顶层目录插入 previewgroupprovider 上下文组件,导出 usepreviewgroup、usepreviewgroupdispatch 读写方法。
'use client' import react from 'react' import { image as antdimage } from 'antd' import { findindex } from 'lodash' import { isimage } from '@/components/preview/ext-rxp' import { usereplacepathname } from '@/components/use-replace-pathname' import createctx from '@/lib/create-ctx' import { usereaddircontext } from '@/app/path/readdir-context' export const previewgroupcontent = createctx<string>() export const usepreviewgroup = previewgroupcontent.usestore export const usepreviewgroupdispatch = previewgroupcontent.usedispatch const antdimagepreviewgroup: react.fc<react.propswithchildren> = ({ children }) => { const { staticpath } = usereplacepathname() const readdir_list = usereaddircontext() const image_list = readdir_list.filter((item) => isimage(item.name)) const name = usepreviewgroup() const previewgroupdispatch = usepreviewgroupdispatch() return ( <antdimage.previewgroup preview={{ visible: !!name, current: findindex(image_list, { name }), onvisiblechange: () => { previewgroupdispatch('') }, onchange: (current) => { previewgroupdispatch(image_list[current].name) }, }} items={image_list.map(({ name }) => staticpath(name))} > {children} </antdimage.previewgroup> ) } const previewgroupprovider: react.fc<{ children: react.reactnode }> = ({ children }) => { return ( <previewgroupcontent.contextprovider value={''}> <antdimagepreviewgroup>{children}</antdimagepreviewgroup> </previewgroupcontent.contextprovider> ) } export default previewgroupprovider
文件路径:explorer/src/components/use-replace-pathname.ts
添加一个获取不同路径的hooks
- replace\_pathname 将不需要的一级路径 /path/ 过滤掉
- joinsearchpath 拼接过滤掉 /path/ 的 pathname
- joinpath 拼接未过滤的 pathname
- staticpath 拼接得到获取文件地址
import { usepathname } from 'next/navigation' export const pathexp = /(^\/)?path/ export const encodepathitem = (path: string) => { return path .split('/') .map((text) => encodeuricomponent(text)) .join('/') } export const usereplacepathname = () => { const pathname = decodeuricomponent(usepathname() || '') const replace_pathname = pathname.replace(pathexp, '') const joinsearchpath = (path: string) => encodepathitem(`${replace_pathname}/${path}`) const joinpath = (path: string) => encodepathitem(`${pathname}/${path}`) const staticpath = (path: string) => `/static${joinsearchpath(path)}` return { pathname: pathname, replace_pathname: replace_pathname, joinsearchpath: joinsearchpath, joinpath: joinpath, staticpath: staticpath, } }
文件路径:explorer/src/app/path/[[...path]]/card-display.tsx
将 preview 组件插入 list item 内
... import preview from '@/components/preview' const carddisplay: react.fc = () => { const pathname = usepathname() const readdir = usereaddircontext() const column = usecardcolumncontext() return ( <list ... <div style={{ position: 'absolute', width: '100%', height: '100%' }}> <preview item={item} /> </div> ...
文件路径:explorer/src/app/path/[[...path]]/page.tsx
将 previewgroupprovider 组件插入最顶部
... import previewgroupprovider from '@/components/preview/proview-group-context' const page: react.fc = () => { const display_type = usedisplaytypecontext() return <previewgroupprovider>{display_type === 'table' ? <tabledisplay /> : <carddisplay />}</previewgroupprovider> } export default page
效果
git-repo
以上就是node文件资源管理器的图片预览从零实现的详细内容,更多关于node文件图片预览的资料请关注代码网其它相关文章!
发表评论