node文件資源管理器的圖片預(yù)覽從零實(shí)現(xiàn)
使用技術(shù)
- 使用 Next.js 的 Image 組件顯示圖片。自帶圖片壓縮生成快速預(yù)覽的 webp 格式圖片
- 使用 antd 的 PreviewGroup 組件實(shí)現(xiàn)原圖瀏覽,自帶縮小、放大、上一張、下一張等功能
功能實(shí)現(xiàn)
文件樹
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
預(yù)覽封裝組件,根據(jù)是否為文件夾、視頻、圖片、壓縮包顯示不同的 icon。
點(diǎn)擊圖片時(shí),使用 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 上下文組件,導(dǎo)出 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
添加一個(gè)獲取不同路徑的hooks
- replace\_pathname 將不需要的一級(jí)路徑 /path/ 過(guò)濾掉
- joinSearchPath 拼接過(guò)濾掉 /path/ 的 pathname
- joinPath 拼接未過(guò)濾的 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 內(nèi)
... 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文件資源管理器的圖片預(yù)覽從零實(shí)現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于node文件圖片預(yù)覽的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Node.js在child_process域和錯(cuò)誤冒泡及捕獲實(shí)踐
這篇文章主要為大家介紹了Node.js在child_process域和錯(cuò)誤冒泡及捕獲實(shí)踐示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11使用Node和Puppeteer實(shí)現(xiàn)批量生成PDF
這篇文章主要為大家詳細(xì)介紹了使用Node.js和Puppeteer庫(kù)將網(wǎng)頁(yè)內(nèi)容轉(zhuǎn)換為PDF文件的過(guò)程,文中的示例代碼講解詳細(xì),有需要的小伙伴可以了解下2024-11-11node.js降低版本的方式詳解(解決sass和node.js沖突問(wèn)題)
這篇文章主要介紹了node.js降低版本的方式(解決sass和node.js沖突),本文是因?yàn)閟ass版本和node版本不匹配(可以找一下對(duì)應(yīng)的版本),本文給大家詳細(xì)講解,需要的朋友可以參考下2023-02-02npm?install?-g?@vue/cli常見(jiàn)問(wèn)題解決匯總
這篇文章主要給大家介紹了關(guān)于npm?install?-g?@vue/cli常見(jiàn)問(wèn)題解決的相關(guān)資料,文中通過(guò)實(shí)例代碼將解決的方式介紹的非常詳細(xì),對(duì)遇到這個(gè)問(wèn)題的朋友具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-08-08node.js WEB開發(fā)中圖片驗(yàn)證碼的實(shí)現(xiàn)方法
這篇文章主要介紹了node.js WEB開發(fā)中圖片驗(yàn)證碼的實(shí)現(xiàn)方法,使用ccap模塊實(shí)現(xiàn),需要的朋友可以參考下2014-06-06淺談node中的exports與module.exports的關(guān)系
本篇文章主要介紹了淺談node中的exports與module.exports的關(guān)系,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08Node.js編寫爬蟲的基本思路及抓取百度圖片的實(shí)例分享
這篇文章主要介紹了Node.js編寫爬蟲的基本思路及抓取百度圖片的實(shí)例分享,其中作者提到了需要特別注意GBK轉(zhuǎn)碼的轉(zhuǎn)碼問(wèn)題,需要的朋友可以參考下2016-03-03node.JS事件機(jī)制與events事件模塊的使用方法詳解
本文將詳細(xì)介紹nodeJS事件機(jī)制與events事件模塊的使用方2020-02-02