最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JS實(shí)現(xiàn)面包屑導(dǎo)航功能從零開(kāi)始示例

 更新時(shí)間:2023年12月21日 16:25:13   作者:寒露  
這篇文章主要為大家介紹了JS實(shí)現(xiàn)面包屑導(dǎo)航功能從零開(kāi)始示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

面包屑導(dǎo)航

url:domain/path/[[…path]]

目前可以通過(guò) url 的的結(jié)構(gòu)信息定位當(dāng)前目錄的情況,但是無(wú)法快速的前進(jìn)與后退。所以使用“面包屑”來(lái)完成這一功能

功能實(shí)現(xiàn)

安裝依賴(lài)

cd /explorer
pnpm i axios ahooks

文件樹(shù)

explorer/src/app/path/[[...path]]/layout.tsx
explorer/src/app/path/api/readdir/route.ts
explorer/src/components/breadcrumb-dropdown-readdir/index.tsx
explorer/src/components/explorer-breadcrumb/index.tsx
explorer/src/components/use-replace-pathname.ts

文件路徑:explorer/src/app/path/api/readdir/route.ts

新增一個(gè)獲取指定目錄的接口

import { NextRequest, NextResponse } from 'next/server'
import { readdir } from '@/explorer-manager/src/main.mjs'
export type SearchParamsType = {
  path: string
  only_dir: '0' | '1'
  only_file: '0' | '1'
  has_file_stat: '0' | '1'
}
export const GET = async (req: NextRequest) => {
  const { path, only_dir, only_file, has_file_stat } = Object.fromEntries(req.nextUrl.searchParams) as SearchParamsType
  return NextResponse.json({ readdir: readdir(path, { only_dir, only_file, has_file_stat }) })
}

文件路徑:explorer/src/app/path/[[...path]]/layout.tsx

將面包屑組件添加至 layout 的 Card 組件 title 部分。

import React from 'react'
import { readdir } from '@/explorer-manager/src/main.mjs'
import { PathContextProvider } from '@/app/path/context'
import { Card } from 'antd'
import ExplorerBreadcrumb from '@/components/explorer-breadcrumb'
const Layout: React.FC<React.PropsWithChildren & { params: { path: string[] } }> = ({
  children,
  params: { path = [] },
}) => {
  const readdirList = readdir(path.join('/'), { only_dir: '0', only_file: '0', has_file_stat: '1' })
  return (
    <PathContextProvider value={readdirList}>
      <Card title={<ExplorerBreadcrumb />}>{children}</Card>
    </PathContextProvider>
  )
}
export default Layout

文件路徑:explorer/src/components/explorer-breadcrumb/index.tsx

面包屑組件,使用 Antd 的 Breadcrumb 組件。跟目錄"/"使用 home icon 替代

'use client'
import React from 'react'
import Link from 'next/link'
import { HomeOutlined } from '@ant-design/icons'
import { usePathname } from 'next/navigation'
import { Breadcrumb, Space } from 'antd'
import BreadcrumbDropdownReaddir from '@/components/breadcrumb-dropdown-readdir'
type ItemType = { title: string; href: string }
const ExplorerBreadcrumb: React.FC = () => {
  const pathname = usePathname() || ''
  return (
    <Space>
      <Breadcrumb
        items={decodeURIComponent(pathname)
          .split('/')
          .filter(Boolean)
          .reduce<ItemType[]>((p, c) => {
            const last = p[p.length - 1]
            return p.concat({ title: c, href: [last?.href, c].join('/') })
          }, [])
          .map(({ title, href }, k, { length }) => {
            return {
              title:
                length === k + 1 && length !== 1 ? (
                  title
                ) : (
                  <BreadcrumbDropdownReaddir title={title} href={href}>
                    <Link href={href}>{k === 0 ? <HomeOutlined /> : title}</Link>
                  </BreadcrumbDropdownReaddir>
                ),
            }
          })}
      />
    </Space>
  )
}
export default ExplorerBreadcrumb

文件路徑:explorer/src/components/breadcrumb-dropdown-readdir/index.tsx

鼠標(biāo) hover 某個(gè)路徑時(shí),下拉出現(xiàn)當(dāng)前路徑下文件夾菜單,方便快速跳轉(zhuǎn)。

當(dāng)菜單超出最大高度時(shí)滾動(dòng)顯示。會(huì)高亮當(dāng)前路徑上的文件。使用 dom 的 scrollIntoView 方法,確保高亮的菜單在可視區(qū)域內(nèi)。

顯示時(shí)對(duì)菜單項(xiàng)進(jìn)行 decodeURIComponent 處理,保證顯示的文本正確。

import React, { useRef } from 'react'
import { Dropdown, Menu } from 'antd'
import { useMount, useRequest } from 'ahooks'
import axios from 'axios'
import { ReaddirListType } from '@/explorer-manager/src/type'
import { encodePathItem, pathExp } from '@/components/use-replace-pathname'
import Link from 'next/link'
import { FolderOpenOutlined, FolderOutlined } from '@ant-design/icons'
import { usePathname } from 'next/navigation'
const ScrollIntoView: React.FC<{ is_open: boolean; className?: string }> = ({ is_open, className }) => {
  const ref = useRef<HTMLDivElement>(null)
  useMount(() => {
    is_open && ref.current?.scrollIntoView({ block: 'center', behavior: 'instant' })
  })
  return is_open ? <FolderOpenOutlined ref={ref} className={className} /> : <FolderOutlined className={className} />
}
const BreadcrumbDropdownReaddir: React.FC<React.PropsWithChildren & { title: string; href: string }> = ({
  children,
  href,
  title,
}) => {
  const pathname = usePathname() || ''
  const { data = [], runAsync } = useRequest(
    () =>
      axios
        .get<{ readdir: ReaddirListType }>('/path/api/readdir', {
          params: { path: href.replace(pathExp, ''), only_dir: 1 },
        })
        .then(({ data: { readdir } }) => {
          return readdir
        }),
    { manual: true, cacheKey: `readdir-${href}`, staleTime: 60 * 1000 },
  )
  const open_dit_text =
    decodeURIComponent(pathname).split([title, '/'].join('')).pop()?.split('/').filter(Boolean).shift() || ''
  return (
    <Dropdown
      destroyPopupOnHide={true}
      arrow={true}
      trigger={['hover']}
      dropdownRender={() => {
        return (
          <Menu
            selectedKeys={[open_dit_text]}
            style={{ maxHeight: '50vw', overflow: 'scroll' }}
            items={data?.map((item) => {
              const is_open = open_dit_text === item.name
              return {
                label: (
                  <Link href={encodePathItem(`${href}/${item.name}`)} prefetch={false}>
                    {item.name}
                  </Link>
                ),
                key: item.name,
                icon: <ScrollIntoView is_open={is_open} />,
              }
            })}
          />
        )
      }}
      onOpenChange={(open) => {
        open && runAsync().then()
      }}
    >
      {children}
    </Dropdown>
  )
}
export default BreadcrumbDropdownReaddir

文件路徑:explorer/src/components/use-replace-pathname.ts

對(duì)路徑進(jìn)行操作 hooks 文件,對(duì)路徑字符串項(xiàng) encodeURIComponent 處理

export const pathExp = /(^\/)?path/
export const encodePathItem = (path: string) => {
  return path
    .split('/')
    .map((text) => encodeURIComponent(text))
    .join('/')
}

效果

git-repo

yangWs29/share-explorer

以上就是JS實(shí)現(xiàn)面包屑導(dǎo)航功能從零開(kāi)始示例的詳細(xì)內(nèi)容,更多關(guān)于JS面包屑導(dǎo)航的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • JavaScript實(shí)現(xiàn)生成隨機(jī)密碼的示例詳解

    JavaScript實(shí)現(xiàn)生成隨機(jī)密碼的示例詳解

    使用JavaScript我們可以輕松地在客戶(hù)端生成隨機(jī)密碼,本文我們將實(shí)現(xiàn)一個(gè)簡(jiǎn)單的隨機(jī)密碼生成器,能夠生成指定長(zhǎng)度和包含特定字符集的密碼,有需要的可以參考下
    2024-01-01
  • JavaScript中如何計(jì)算字符串文本的寬度

    JavaScript中如何計(jì)算字符串文本的寬度

    這篇文章主要介紹了JavaScript中如何計(jì)算字符串文本的寬度問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • js事件機(jī)制----捕獲與冒泡機(jī)制實(shí)例分析

    js事件機(jī)制----捕獲與冒泡機(jī)制實(shí)例分析

    這篇文章主要介紹了js事件機(jī)制----捕獲與冒泡機(jī)制,結(jié)合實(shí)例形式分析了js事件機(jī)制中捕獲與冒泡機(jī)制相關(guān)原理、操作技巧與注意事項(xiàng),需要的朋友可以參考下
    2020-05-05
  • JavaScript實(shí)現(xiàn)簡(jiǎn)單拖拽效果

    JavaScript實(shí)現(xiàn)簡(jiǎn)單拖拽效果

    這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)簡(jiǎn)單拖拽效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • JSON.parse處理非標(biāo)準(zhǔn)Json數(shù)據(jù)出錯(cuò)的解決

    JSON.parse處理非標(biāo)準(zhǔn)Json數(shù)據(jù)出錯(cuò)的解決

    這篇文章主要介紹了JSON.parse處理非標(biāo)準(zhǔn)Json數(shù)據(jù)出錯(cuò)的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • 基于javascript實(shí)現(xiàn)仿百度輸入框自動(dòng)匹配功能

    基于javascript實(shí)現(xiàn)仿百度輸入框自動(dòng)匹配功能

    這篇文章主要介紹了基于javascript實(shí)現(xiàn)仿百度輸入框自動(dòng)匹配功能的相關(guān)資料,需要的朋友可以參考下
    2016-01-01
  • javascript replace()正則替換實(shí)現(xiàn)代碼

    javascript replace()正則替換實(shí)現(xiàn)代碼

    javascript-replace()基礎(chǔ),一次完成將"<,>"替換"&lt;&gt;"實(shí)例
    2010-02-02
  • JavaScript基礎(chǔ)知識(shí)之方法匯總結(jié)

    JavaScript基礎(chǔ)知識(shí)之方法匯總結(jié)

    本文給大家分享了javascript基礎(chǔ)知識(shí),包括數(shù)組的方法,函數(shù)的方法,數(shù)字的方法,對(duì)象的方法,字符串的方法,常規(guī)方法,正則表達(dá)式方法,本文介紹的非常詳細(xì),具有參考價(jià)值特此分享供大家參考
    2016-01-01
  • TypeScript中類(lèi)型縮小的方式

    TypeScript中類(lèi)型縮小的方式

    本文探討了TypeScript中用于提升代碼安全性的類(lèi)型縮小技術(shù),包括類(lèi)型斷言通過(guò)as或<>,使用instanceof檢查對(duì)象實(shí)例,in關(guān)鍵字驗(yàn)證對(duì)象屬性,以及自定義類(lèi)型保護(hù)函數(shù)進(jìn)行更復(fù)雜的類(lèi)型檢查,感興趣的可以了解一下
    2026-05-05
  • js電話(huà)號(hào)碼驗(yàn)證方法

    js電話(huà)號(hào)碼驗(yàn)證方法

    JS電話(huà)號(hào)碼驗(yàn)證是比較常的一種驗(yàn)證,下邊給出一個(gè)JavaScript驗(yàn)證電話(huà)號(hào)碼的小例子。國(guó)內(nèi)固定電話(huà)都是七位或8位的數(shù)字組成的,還可以帶有長(zhǎng)途的區(qū)號(hào)。
    2015-09-09

最新評(píng)論

丰顺县| 石河子市| 阿合奇县| 遂宁市| 衡水市| 宁陕县| 文成县| 东兰县| 临洮县| 四子王旗| 行唐县| 化州市| 定襄县| 通化市| 济南市| 资中县| 扎囊县| 二连浩特市| 天长市| 荆州市| 平原县| 浮梁县| 赣榆县| 昌黎县| 商都县| 苗栗县| 德昌县| 泰和县| 鄂伦春自治旗| 常州市| 彭水| 罗甸县| 齐齐哈尔市| 德州市| 通化县| 若尔盖县| 谷城县| 嵩明县| 邯郸县| 休宁县| 留坝县|