再次优化筛选

This commit is contained in:
yml2213
2026-06-13 18:19:45 +08:00
parent 55326b7d06
commit 9965150521
5 changed files with 301 additions and 7 deletions
@@ -1,12 +1,16 @@
import { describe, expect, it } from 'vitest'
import { describe, expect, it, vi } from 'vitest'
import type { LocationQuery } from 'vue-router'
import {
clearStoredHomeQuery,
decodeHomeQueryJson,
encodeHomeQueryJson,
hasHomeQueryValues,
isSameQuery,
mergeHomeQuery,
readStoredHomeQuery,
readQueryNumber,
readQueryString,
storeHomeQuery,
} from '@/features/listings/composables/useHomeFilterQuery'
describe('useHomeFilterQuery', () => {
@@ -51,4 +55,27 @@ describe('useHomeFilterQuery', () => {
server: [],
})
})
it('应该判断并缓存首页筛选参数', () => {
const storage = new Map<string, string>()
vi.stubGlobal('window', {
sessionStorage: {
getItem: (key: string) => storage.get(key) ?? null,
setItem: (key: string, value: string) => storage.set(key, value),
removeItem: (key: string) => storage.delete(key),
},
})
const storageKey = 'hfb.home.filters.test'
const query = { keyword: '测试', zone: 'gift' }
try {
expect(hasHomeQueryValues(query, ['keyword', 'zone'])).toBe(true)
storeHomeQuery(storageKey, query)
expect(readStoredHomeQuery(storageKey)).toEqual(query)
clearStoredHomeQuery(storageKey)
expect(readStoredHomeQuery(storageKey)).toEqual({})
} finally {
vi.unstubAllGlobals()
}
})
})
@@ -29,13 +29,16 @@ export const mobileHomeFilterQueryKeys = ['keyword', 'sort', 'zone', 'filters',
export type HomeQueryValue = string | number | undefined
export function readQueryString(query: LocationQuery, key: string) {
export const desktopHomeFilterStorageKey = 'hfb.home.filters.desktop'
export const mobileHomeFilterStorageKey = 'hfb.home.filters.mobile'
export function readQueryString(query: LocationQuery | LocationQueryRaw, key: string) {
const value = query[key]
if (Array.isArray(value)) return String(value[0] || '')
return typeof value === 'string' ? value : ''
return value === undefined || value === null ? '' : String(value)
}
export function readQueryNumber(query: LocationQuery, key: string) {
export function readQueryNumber(query: LocationQuery | LocationQueryRaw, key: string) {
const value = readQueryString(query, key)
if (value === '') return undefined
const number = Number(value)
@@ -66,12 +69,62 @@ export function isSameQuery(left: LocationQuery, right: LocationQueryRaw) {
return stableQuerySignature(left) === stableQuerySignature(right)
}
export function hasHomeQueryValues(
query: LocationQuery | LocationQueryRaw,
keys: readonly string[]
) {
return keys.some(key => {
const value = query[key]
if (Array.isArray(value)) return value.some(item => item !== undefined && item !== '')
return value !== undefined && value !== ''
})
}
export function readStoredHomeQuery(storageKey: string): LocationQueryRaw {
if (typeof window === 'undefined') return {}
try {
const raw = window.sessionStorage.getItem(storageKey)
if (!raw) return {}
const parsed = JSON.parse(raw)
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return {}
const query: LocationQueryRaw = {}
for (const [key, value] of Object.entries(parsed)) {
if (typeof value === 'string' && value !== '') query[key] = value
}
return query
} catch {
return {}
}
}
export function storeHomeQuery(storageKey: string, query: LocationQueryRaw) {
if (typeof window === 'undefined') return
try {
window.sessionStorage.setItem(storageKey, JSON.stringify(query))
} catch {
// 浏览器禁用 sessionStorage 时忽略,URL 仍然可用。
}
}
export function clearStoredHomeQuery(storageKey: string) {
if (typeof window === 'undefined') return
try {
window.sessionStorage.removeItem(storageKey)
} catch {
// 浏览器禁用 sessionStorage 时忽略。
}
}
export function encodeHomeQueryJson(value: unknown) {
if (!hasMeaningfulValue(value)) return undefined
return JSON.stringify(value)
}
export function decodeHomeQueryJson<T>(query: LocationQuery, key: string, fallback: T): T {
export function decodeHomeQueryJson<T>(
query: LocationQuery | LocationQueryRaw,
key: string,
fallback: T
): T {
const raw = readQueryString(query, key)
if (!raw) return fallback
try {
@@ -13,11 +13,16 @@ import {
} from '@/features/listings/api/listingOptions'
import { useHomeFilters } from '@/features/listings/composables/useHomeFilters'
import {
clearStoredHomeQuery,
desktopHomeFilterStorageKey,
desktopHomeFilterQueryKeys,
hasHomeQueryValues,
isSameQuery,
mergeHomeQuery,
readStoredHomeQuery,
readQueryNumber,
readQueryString,
storeHomeQuery,
type HomeQueryValue,
} from '@/features/listings/composables/useHomeFilterQuery'
import { useListingQuery } from '@/features/listings/composables/useListingQuery'
@@ -151,6 +156,7 @@ function updateFilters(partial: Partial<typeof filters>) {
}
function handleResetFilters() {
clearStoredHomeQuery(desktopHomeFilterStorageKey)
resetFilters()
activeZone.value = 'all'
sortBy.value = 'recommended'
@@ -158,7 +164,10 @@ function handleResetFilters() {
}
function applyRouteQueryToHomeState() {
const query = route.query
const storedQuery = readStoredHomeQuery(desktopHomeFilterStorageKey)
const query = hasHomeQueryValues(route.query, desktopHomeFilterQueryKeys)
? route.query
: storedQuery
filters.keyword = readQueryString(query, 'keyword')
filters.server = readQueryString(query, 'server')
filters.region = readQueryString(query, 'region')
@@ -193,6 +202,9 @@ function syncHomeQuery() {
desktopHomeFilterQueryKeys,
buildDesktopHomeQueryValues()
)
if (hasHomeQueryValues(query, desktopHomeFilterQueryKeys)) {
storeHomeQuery(desktopHomeFilterStorageKey, query)
}
if (isSameQuery(route.query, query)) return
router.replace({ path: '/', query })
}
@@ -224,6 +236,7 @@ function buildDesktopHomeQueryValues(): Record<string, HomeQueryValue> {
}
}
syncHomeQuery()
loadHome()
</script>
@@ -23,12 +23,17 @@ import {
} from '@/features/listings/api/homeConfig'
import MobileHomeFilterSheet, { type FilterSection } from './MobileHomeFilterSheet.vue'
import {
clearStoredHomeQuery,
decodeHomeQueryJson,
encodeHomeQueryJson,
hasHomeQueryValues,
isSameQuery,
mergeHomeQuery,
mobileHomeFilterStorageKey,
mobileHomeFilterQueryKeys,
readStoredHomeQuery,
readQueryString,
storeHomeQuery,
type HomeQueryValue,
} from '@/features/listings/composables/useHomeFilterQuery'
import {
@@ -384,6 +389,7 @@ function selectZone(zoneKey: string) {
}
function clearFilters() {
clearStoredHomeQuery(mobileHomeFilterStorageKey)
selectedFilters.value = {}
rangeFilters.value = {}
searchValue.value = ''
@@ -466,7 +472,10 @@ function parseOptionalNumber(value: string) {
}
function applyRouteQueryToMobileState() {
const query = route.query
const storedQuery = readStoredHomeQuery(mobileHomeFilterStorageKey)
const query = hasHomeQueryValues(route.query, mobileHomeFilterQueryKeys)
? route.query
: storedQuery
searchValue.value = readQueryString(query, 'keyword')
activeSort.value = readQueryString(query, 'sort') || 'recommended'
activeZone.value = readQueryString(query, 'zone') || 'all'
@@ -480,6 +489,9 @@ function applyRouteQueryToMobileState() {
function syncMobileHomeQuery() {
const query = mergeHomeQuery(route.query, mobileHomeFilterQueryKeys, buildMobileHomeQueryValues())
if (hasHomeQueryValues(query, mobileHomeFilterQueryKeys)) {
storeHomeQuery(mobileHomeFilterStorageKey, query)
}
if (isSameQuery(route.query, query)) return
router.replace({ path: route.path, query })
}
@@ -572,6 +584,8 @@ function chipTone(label: string) {
if (label.includes('方便')) return 'time'
return 'default'
}
syncMobileHomeQuery()
</script>
<template>