JavaScript 的 array sort 方法对字符串的排序有些问题。
纯数字
[1, 2, 3, 11].sort()
=> [1, 11, 2, 3]
字符串
['a', 'e', 'b', 'c', 'd'].sort()
=> ['a', 'b', 'c', 'd', 'e']
数字加字符串
['a-1', 'a-2', 'a-2', 'a-11'].sort()
=> ['a-1', 'a-11', 'a-2', 'a-3']
上面的例子发现,字符串的可以排序正常,数字的 11 会拍在 2 的前面。纯数字的可以通过 sort((a, b) => a - b) 的回调控制挣钱排序。
如果涉及到"字符串+数字"的时候,简单的 a - b 无法完成排序任务。
这里引用一个自然排序的依赖 natural-compare-lite可以正确处理文件名的排序问题。
开发
explorer
安装依赖
pnpm i natural-compare-lite
pnpm i @types/natural-compare-lite -D
创建 sort 排序 context 组件,并创建四个排序方法
- 时间的正排序与逆排序
- 文件名正排序与逆排序
对文件名的排序使用 naturalCompare 依赖方法。
'use client'
import naturalCompare from 'natural-compare-lite'
import { ReaddirItemType } from '@/explorer-manager/src/type'
import createCtx from '@/lib/create-ctx'
import React from 'react'
export type SortAction = (a: ReaddirItemType, b: ReaddirItemType) => number
export const nameAscSort: SortAction = (a, b) => naturalCompare(a.name, b.name)
export const dateAscSort: SortAction = (a, b) => (a?.stat?.mtimeMs || 0) - (b?.stat?.mtimeMs || 0)
export const nameDescSort: SortAction = (a, b) => naturalCompare(b.name, a.name)
export const dateDescSort: SortAction = (a, b) => (b?.stat?.mtimeMs || 0) - (a?.stat?.mtimeMs || 0)
export const sortMap = {
asc_name: nameAscSort,
asc_date: dateAscSort,
desc_name: nameDescSort,
desc_date: dateDescSort,
}
export const SortContext = createCtx<'asc_name' | 'asc_date' | 'desc_name' | 'desc_date'>()
export const useSortStore = SortContext.useStore
export const useSortDispatch = SortContext.useDispatch
export const SortProvider: React.FC<React.PropsWithChildren> = ({ children }) => {
return <SortContext.ContextProvider value="asc_name">{children}</SortContext.ContextProvider>
}
创建一个控制排序的下拉菜单组件
'use client'
import React from 'react'
import { Button, Dropdown } from 'antd'
import { SortAscendingOutlined, SortDescendingOutlined } from '@ant-design/icons'
import { useSortDispatch, useSortStore } from '@/components/readdir-sort/sort-context'
const ReaddirSort: React.FC = () => {
const sort = useSortStore()
const sortDispatch = useSortDispatch()
return (
<Dropdown
placement="top"
arrow={true}
trigger={['hover', 'click']}
menu={{
selectedKeys: [sort],
items: [
{
key: 'asc_name',
icon: <SortAscendingOutlined />,
onClick: () => {
sortDispatch('asc_name')
},
label: '名称正排',
},
{
key: 'desc_name',
icon: <SortDescendingOutlined />,
onClick: () => {
sortDispatch('desc_name')
},
label: '名称倒排',
},
{
key: 'asc_date',
icon: <SortAscendingOutlined />,
onClick: () => {
sortDispatch('asc_date')
},
label: '时间正排',
},
{
key: 'desc_date',
icon: <SortDescendingOutlined />,
onClick: () => {
sortDispatch('desc_date')
},
label: '时间倒排',
},
],
}}
>
<Button icon={<SortAscendingOutlined />} />
</Dropdown>
)
}
export default ReaddirSort
为 readdir-context 内的 useReaddirContext 读取 sort 属性对 readdir_list 进行 sort 排序
export const useReaddirContext = () => {
const readdir_list = ReaddirContext.useStore()
const sort = useSortStore()
return readdir_list.sort(sortMap[sort])
}
为保证能正确读取到 useSortStore 属性。需要将 SortProvider 插入 ReaddirProvider 上下文组件之前。
...
export const PathContextProvider: React.FC<React.ProviderProps<ReaddirListType>> = ({ value, children }) => {
return (
<SortProvider>
<ReaddirProvider value={value}>
...
<VideoInfoProvider>{children}</VideoInfoProvider>
...
</ReaddirProvider>
</SortProvider>
)
}
到此,对文件排序功能完成
效果
截屏2023-12-24 10.51.36.png