AI-News/frontend/app/composables/useArticleNavContext.js

119 lines
2.9 KiB
JavaScript
Raw Permalink Normal View History

2025-12-04 10:04:21 +08:00
// app/composables/useArticleNavContext.js
// 维护文章列表上下文(顺序、当前位置)供详情页/抽屉使用
import { computed } from 'vue'
const STORAGE_KEY = 'article:list:context'
function useStorage () {
if (process.server) return null
return window.sessionStorage
}
function readPersisted () {
try {
const store = useStorage()
if (!store) return null
const raw = store.getItem(STORAGE_KEY)
if (!raw) return null
return JSON.parse(raw)
} catch (err) {
console.warn('[ArticleNav] read persist failed', err)
return null
}
}
function writePersisted (payload) {
try {
const store = useStorage()
if (!store) return
store.setItem(STORAGE_KEY, JSON.stringify(payload))
} catch (err) {
console.warn('[ArticleNav] write persist failed', err)
}
}
function uniqSlugs (slugs = []) {
const seen = new Set()
const res = []
for (const s of slugs) {
if (!s || seen.has(s)) continue
seen.add(s)
res.push(s)
}
return res
}
export function useArticleNavContext () {
const state = useState('article:nav', () => {
// SSR 时返回空状态,客户端会在下面恢复
if (process.server) {
return {
listId: '',
slugs: [],
current: ''
}
}
// 客户端首次初始化时从 sessionStorage 恢复
return readPersisted() || {
listId: '',
slugs: [],
current: ''
}
})
// 客户端挂载时,确保从 sessionStorage 恢复状态
if (process.client) {
const persisted = readPersisted()
if (persisted && persisted.slugs && persisted.slugs.length > 0) {
// 如果 sessionStorage 中有数据,但 state 是空的,则恢复
if (!state.value.slugs || state.value.slugs.length === 0) {
console.log('[ArticleNav] 从 sessionStorage 恢复导航上下文:', persisted)
state.value = persisted
}
}
}
const index = computed(() => {
if (!state.value.current) return -1
return state.value.slugs.findIndex((s) => s === state.value.current)
})
const prevSlug = computed(() => {
const i = index.value
return i > 0 ? state.value.slugs[i - 1] : ''
})
const nextSlug = computed(() => {
const i = index.value
return i >= 0 && i < state.value.slugs.length - 1 ? state.value.slugs[i + 1] : ''
})
const hasNav = computed(() => Boolean(state.value.slugs.length))
function setList (listId, slugs) {
if (!Array.isArray(slugs)) return
state.value.listId = listId || ''
state.value.slugs = uniqSlugs(slugs.filter(Boolean))
writePersisted(state.value)
}
function setCurrent (slug) {
const s = slug || ''
state.value.current = s
if (s && !state.value.slugs.includes(s)) {
state.value.slugs = uniqSlugs([...(state.value.slugs || []), s])
}
writePersisted(state.value)
}
return {
state,
index,
prevSlug,
nextSlug,
hasNav,
setList,
setCurrent
}
}