feat: 文章列表页分页路由映射
This commit is contained in:
parent
36aa6c99b5
commit
12917050c8
@ -1,8 +1,8 @@
|
||||
import { usePageLang } from '@vuepress/client'
|
||||
import { useBlogPostData } from '@vuepress-plume/plugin-blog-data/client'
|
||||
import { computed, ref } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
import type { PlumeThemeBlogPostItem } from '../../shared/index.js'
|
||||
import { useLocaleLink, useThemeLocaleData } from '../composables/index.js'
|
||||
import { useLocaleLink, useRouteQuery, useThemeLocaleData } from '../composables/index.js'
|
||||
import { getRandomColor, toArray } from '../utils/index.js'
|
||||
|
||||
export function useLocalePostList() {
|
||||
@ -33,10 +33,18 @@ export function usePostListControl() {
|
||||
return next.sticky > prev.sticky ? 1 : -1
|
||||
}),
|
||||
...otherList,
|
||||
]
|
||||
] as PlumeThemeBlogPostItem[]
|
||||
})
|
||||
|
||||
const page = ref(1)
|
||||
const page = useRouteQuery('p', 1, {
|
||||
mode: 'push',
|
||||
transform(val) {
|
||||
const page = Number(val)
|
||||
if (!Number.isNaN(page) && page > 0)
|
||||
return page
|
||||
return 1
|
||||
},
|
||||
})
|
||||
|
||||
const totalPage = computed(() => {
|
||||
if (blog.value.pagination === false)
|
||||
@ -133,14 +141,15 @@ export function useTags() {
|
||||
}))
|
||||
})
|
||||
|
||||
const postList = ref<ShortPostItem[]>([])
|
||||
const currentTag = ref<string>()
|
||||
const currentTag = useRouteQuery<string>('tag')
|
||||
|
||||
const handleTagClick = (tag: string) => {
|
||||
currentTag.value = tag
|
||||
postList.value = list.value.filter((item) => {
|
||||
const postList = computed<ShortPostItem[]>(() => {
|
||||
if (!currentTag.value)
|
||||
return []
|
||||
|
||||
return list.value.filter((item) => {
|
||||
if (item.tags)
|
||||
return toArray(item.tags).includes(tag)
|
||||
return toArray(item.tags).includes(currentTag.value)
|
||||
|
||||
return false
|
||||
}).map(item => ({
|
||||
@ -148,6 +157,10 @@ export function useTags() {
|
||||
path: item.path,
|
||||
createTime: item.createTime.split(' ')[0].replace(/\//g, '-'),
|
||||
}))
|
||||
})
|
||||
|
||||
const handleTagClick = (tag: string) => {
|
||||
currentTag.value = tag
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
126
theme/src/client/composables/useRouteQuery.ts
Normal file
126
theme/src/client/composables/useRouteQuery.ts
Normal file
@ -0,0 +1,126 @@
|
||||
import { customRef, nextTick, toValue, watch } from 'vue'
|
||||
import type { MaybeRef, MaybeRefOrGetter, Ref } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import type { RouteParamValueRaw, Router } from 'vue-router'
|
||||
import { tryOnScopeDispose } from '@vueuse/core'
|
||||
|
||||
export type RouteQueryValueRaw = RouteParamValueRaw | string[]
|
||||
|
||||
export interface ReactiveRouteOptions {
|
||||
/**
|
||||
* Mode to update the router query, ref is also acceptable
|
||||
*
|
||||
* @default 'replace'
|
||||
*/
|
||||
mode?: MaybeRef<'replace' | 'push'>
|
||||
|
||||
/**
|
||||
* Route instance, use `useRoute()` if not given
|
||||
*/
|
||||
route?: ReturnType<typeof useRoute>
|
||||
|
||||
/**
|
||||
* Router instance, use `useRouter()` if not given
|
||||
*/
|
||||
router?: ReturnType<typeof useRouter>
|
||||
}
|
||||
|
||||
export interface ReactiveRouteOptionsWithTransform<V, R> extends ReactiveRouteOptions {
|
||||
/**
|
||||
* Function to transform data before return
|
||||
*/
|
||||
transform?: (val: V) => R
|
||||
}
|
||||
|
||||
const _queue = new WeakMap<Router, Map<string, any>>()
|
||||
|
||||
export function useRouteQuery(
|
||||
name: string
|
||||
): Ref<null | string | string[]>
|
||||
|
||||
export function useRouteQuery<
|
||||
T extends RouteQueryValueRaw = RouteQueryValueRaw,
|
||||
K = T,
|
||||
>(
|
||||
name: string,
|
||||
defaultValue?: MaybeRefOrGetter<T>,
|
||||
options?: ReactiveRouteOptionsWithTransform<T, K>
|
||||
): Ref<K>
|
||||
|
||||
export function useRouteQuery<
|
||||
T extends RouteQueryValueRaw = RouteQueryValueRaw,
|
||||
K = T,
|
||||
>(
|
||||
name: string,
|
||||
defaultValue?: MaybeRefOrGetter<T>,
|
||||
options: ReactiveRouteOptionsWithTransform<T, K> = {},
|
||||
): Ref<K> {
|
||||
const {
|
||||
mode = 'replace',
|
||||
route = useRoute(),
|
||||
router = useRouter(),
|
||||
transform = value => value as any as K,
|
||||
} = options
|
||||
|
||||
if (!_queue.has(router))
|
||||
_queue.set(router, new Map())
|
||||
|
||||
const _queriesQueue = _queue.get(router)!
|
||||
|
||||
let query = route.query[name] as any
|
||||
|
||||
tryOnScopeDispose(() => {
|
||||
query = undefined
|
||||
})
|
||||
|
||||
let _trigger: () => void
|
||||
|
||||
const proxy = customRef<any>((track, trigger) => {
|
||||
_trigger = trigger
|
||||
|
||||
return {
|
||||
get() {
|
||||
track()
|
||||
|
||||
return transform(query !== undefined ? query : toValue(defaultValue))
|
||||
},
|
||||
set(v) {
|
||||
if (query === v)
|
||||
return
|
||||
|
||||
query = v
|
||||
_queriesQueue.set(name, v)
|
||||
|
||||
trigger()
|
||||
|
||||
nextTick(() => {
|
||||
if (_queriesQueue.size === 0)
|
||||
return
|
||||
|
||||
const newQueries = Object.fromEntries(_queriesQueue.entries())
|
||||
_queriesQueue.clear()
|
||||
|
||||
const { params, query, hash } = route
|
||||
|
||||
router[toValue(mode)]({
|
||||
params,
|
||||
query: { ...query, ...newQueries },
|
||||
hash,
|
||||
})
|
||||
})
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
watch(
|
||||
() => route.query[name],
|
||||
(v) => {
|
||||
query = v
|
||||
|
||||
_trigger()
|
||||
},
|
||||
{ flush: 'sync' },
|
||||
)
|
||||
|
||||
return proxy as any as Ref<K>
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user