可直接用 customref 实现 url 查询参数与响应式变量的双向同步:读取时 track 并返回 searchparams 值,写入时用 replacestate 更新 url 并 trigger;需监听 popstate 事件以响应浏览器导航。

可以直接用 customRef 将 URL 查询参数(如 search)映射为响应式变量,实现输入即更新 URL、URL 变化即更新变量的双向同步。
核心思路:监听和写入 URL 的 searchParams
不依赖额外库,只用原生 URLSearchParams 和 history.pushState / replaceState。customRef 负责把「读取 URL 参数」和「修改 URL 参数」封装成响应式行为。
-
get() 中调用
track()并返回当前 URL 中的参数值(例如searchParams.get('q') || '') -
set(newValue) 中更新 URL:先修改
searchParams,再用history.replaceState同步到地址栏(避免产生历史记录),最后调用trigger()通知依赖更新 - 必须监听
popstate事件,捕获浏览器前进/后退时的 URL 变化,并手动触发trigger(),否则变量不会响应
完整可复用的 useUrlQueryParam 实现
以下是一个带错误处理和 cleanup 的封装函数:
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
import { customRef } from 'vue'
export function useUrlQueryParam(key, defaultValue = '') {
const url = new URL(window.location.href)
let value = url.searchParams.get(key) ?? defaultValue
// 监听浏览器导航(前进/后退)
const onPopState = () => {
const newUrl = new URL(window.location.href)
const newValue = newUrl.searchParams.get(key) ?? defaultValue
if (newValue !== value) {
value = newValue
}
}
window.addEventListener('popstate', onPopState)
return customRef((track, trigger) => ({
get() {
track()
return value
},
set(newValue) {
const url = new URL(window.location.href)
if (newValue == null || newValue === '') {
url.searchParams.delete(key)
} else {
url.searchParams.set(key, String(newValue))
}
// 同步到地址栏(不添加历史记录)
history.replaceState(null, '', url)
value = String(newValue)
trigger()
}
}))
}
在组件中使用示例
绑定搜索关键词,URL 自动同步:
import { useUrlQueryParam } from './composables/useUrlQueryParam'
export default {
setup() {
const q = useUrlQueryParam('q')
// 这个计算属性只在 URL 的 q 参数真正变化后才执行
const filteredList = computed(() => {
return list.value.filter(item => item.title.includes(q.value))
})
return { q, filteredList }
}
}
模板中直接使用:<input v-model="q" placeholder="搜索(URL 同步)">
注意事项
- 首次加载时,
value来自当前 URL,确保初始化准确 - 使用
replaceState而非pushState,避免用户点击后退跳回空搜索页 - 组件卸载时建议移除
popstate监听器(Vue 3.4+ 在 unmounted 钩子中自动清理,旧版需手动onUnmounted(() => window.removeEventListener('popstate', onPopState))) - 若需支持多个参数或 hash 模式,可扩展该函数,传入解析策略










