Vue3 Composition API不使用Vuex实现多路由搜索筛选条件持久化方案问询
问题根因
你当前的实现偶发失效主要有两个核心原因:
- 若
activeFilters定义在单个路由组件内部,不同路由会各自维护独立的响应式实例,路由切换时新旧组件的初始化、销毁时序可能导致localStorage读写冲突,出现数据不一致。 - 直接操作localStorage属性、未做异常捕获的写法存在兼容性和稳定性问题:部分浏览器不支持直接给localStorage挂载自定义属性,若存储的内容存在不可序列化的字段、或者之前存储的JSON格式损坏,都会导致读写失败。
正确解决方案
建议把筛选逻辑抽为全局公共的组合式函数(Composable),保证所有路由复用同一个响应式状态实例,同时加异常兼容逻辑:
1. 新增公共组合式函数 composables/useSearchFilters.js
import { ref, watchEffect, onUnmounted } from 'vue' // 全局单例响应式状态,所有路由复用同一个实例 const activeFilters = ref( // 初始化加异常捕获,避免本地存储的非法JSON导致页面报错 (() => { try { return JSON.parse(localStorage.getItem('searchFilters')) || [] } catch (err) { console.warn('本地筛选条件损坏,已重置', err) return [] } })() ) export function useSearchFilters() { // 自动监听状态变化,无需手动指定deep,状态变更时自动同步到本地存储 const stopWatch = watchEffect(() => { // 使用标准localStorage API,避免直接挂载属性的兼容性问题 localStorage.setItem('searchFilters', JSON.stringify(activeFilters.value)) }) // 封装统一操作方法,避免业务组件直接修改状态 const addFilter = (filterValue) => { activeFilters.value.push({ value: filterValue }) } const removeFilter = (index) => { activeFilters.value.splice(index, 1) } const clearFilters = () => { activeFilters.value = [] localStorage.removeItem('searchFilters') } // 组件卸载时停止监听,防止内存泄漏 onUnmounted(() => { stopWatch() }) return { activeFilters, addFilter, removeFilter, clearFilters } }
2. 路由业务组件中使用
<script setup> import { ref } from 'vue' import { useSearchFilters } from '@/composables/useSearchFilters' const { activeFilters, addFilter, removeFilter } = useSearchFilters() const filtered = ref('') // 新增筛选逻辑 const handleAddFilter = () => { addFilter(filtered.value) filtered.value = '' } </script>
额外优化建议
如果需要区分不同路由页面的筛选条件,避免多页面筛选串掉,可以在存储时加上路由唯一标识:
// 组合式函数中接收路由标识参数 export function useSearchFilters(pageKey = 'common') { const storageKey = `searchFilters_${pageKey}` const activeFilters = ref( (() => { try { return JSON.parse(localStorage.getItem(storageKey)) || [] } catch (err) { console.warn('本地筛选条件损坏,已重置', err) return [] } })() ) // ... 其余逻辑不变,存储时都用storageKey即可 } // 组件使用时传入当前路由的唯一标识 import { useRoute } from 'vue-router' const route = useRoute() const { activeFilters, addFilter } = useSearchFilters(route.name)
内容的提问来源于stack exchange,提问作者Nathan Azevedo
相关产品推荐
相关产品推荐

