再次优化筛选
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user