Vue3 路由传参
在 Vue3 中使用 Vue Router 进行路由跳转时,常常需要向目标页面传递数据。由于 Vue3 的响应式系统采用 Proxy 实现,若直接传递 ref、reactive 等响应式对象,可能导致无法正确序列化或解析。以下总结了可能的问题、原因以及最佳实践。
1. 路由传参方式
1.1 URL Query / Params
在 Vue Router 中,query 和 params 最常用且直观:
query:使用 URL 末尾的 ?key=value 形式传参。
params:声明路由时在 path 中定义占位符,如 /user/:id,然后通过 route.params 读取。
示例:
router.push({
name: "UserDetail",
query: { id: 1 },
});
// 目标组件中:
console.log(route.query.id);
router.push({
name: "UserDetail",
params: { id: 1 },
});
// 目标组件中:
console.log(route.params.id);
1.2 通过 state 传参
从 Vue Router 4.1.4 版本开始,使用 state 方式进行传参: 文档链接
router.push({
path: "/path",
state: { data: "someData" },
});
在目标组件或任意位置可以通过浏览器的 History API 拿到:
const historyParams = history.state.data;
由于 state 方式对数据做了序列化等处理,在传递非响应式对象的场景中非常方便。
2. 响应式对象传参的常见问题
2.1 无法正确序列化
当直接将 Vue 的响应式对象(ref / reactive)传入路由参数时,底层序列化操作会丢失其 Proxy 包装导致报错或无法被完整复制。
示例:
// 错误示例
// row 是 reactive 对象,unref(row) 或 toValue(row) 只能解除最外层 ref
router.push({
name: "addChildAccount",
state: {
childAccountInfo: unref(row),
},
});
这种写法往往会导致在目标页面无法正常获取数据,或只得到空对象。
2.2 unref() 或 toValue() 无法深层去除 Proxy
unref(row):只会对最外层进行处理,若内部属性仍是 reactive / Proxy,则无法彻底释放。
toValue(row):与 unref 类似,也不会进行深层转换。
需要更彻底的方式才能保证数据被正确序列化和传输。
3. 解决方案与最佳实践
3.1 使用 JSON.parse(JSON.stringify())
在路由跳转时,直接将响应式对象转换为纯 JS 对象。
示例:
const routeInfo = {
name: "addChildAccount",
state: {
childAccountInfo: JSON.parse(JSON.stringify(row)),
},
};
3.2 使用 toRaw()
如果你的需求仅限于浅层转换,可以使用 toRaw:
const routeInfo = {
name: "addChildAccount",
state: {
childAccountInfo: toRaw(row),
},
};
- toRaw(row) 可以移除 Proxy 包装,但对于深层嵌套仍非完全深拷贝。
3.3 在目标组件重新创建响应式
通常路由参数只是用于在目标组件初始化数据即可。如果需要在目标组件中保持响应式,建议在目标组件中重新创建 ref 或 reactive:
const routeData = history.state?.data || {};
const formData = reactive({ ...routeData });
4. 补充说明
使用 name 路由可以从语义上更突显目标页面,也更利于维护。
选择 params 或 query 时,应结合业务场景评估;如果只是内部跳转且无需保留在浏览器完整地址栏里时,state 方式相对更方便。
unref / toValue 只能剥离最外层 ref,深层依旧会保留 Proxy,要传递纯数据时需深拷贝。
5. 总结
尽量避免直接在路由中传递响应式对象,如果要传递,请先转换成普通对象(toRaw 或 JSON.parse(JSON.stringify()))。
若传递过去后还要保持响应式,可在目标组件中手动创建新 ref/reactive 并赋值。
选择更合适的参数方式(query / params / state),title、简易 ID 等基础数据可直接用 query 或 params,大对象或内部结构较复杂的数据可考虑使用 state,并确保序列化后再传递。