SSF0SSF0
首页
前端
  • Node
  • Go
  • C#
  • MySql
  • Bash
  • Git
  • Docker
  • VuePress
  • CI/CD
  • 服务器
  • 网站
  • 学习资料
  • 软件
Timeline
Github
标签
分类
首页
前端
  • Node
  • Go
  • C#
  • MySql
  • Bash
  • Git
  • Docker
  • VuePress
  • CI/CD
  • 服务器
  • 网站
  • 学习资料
  • 软件
Timeline
Github
标签
分类
  • HTML

    • html1
    • html2
  • CSS

    • Flex 布局常见问题与解决方案
  • JavaScript

    • 数据类型及引用问题
    • 处理 Blob 类型文件下载问题总结
    • localStorage 与 sessionStorage 区别
    • JavaScript 中的 script 标签问题详解
    • JavaScript 中的`this`指向问题详解
    • SessionStorage踩坑记录:它真的能"只设置一次"吗?
    • 动态加载 JS 脚本方法对比
    • 浏览器页面关闭场景下的数据上报
  • es6

    • Promise
    • es6 模块导出方式全解析
  • Vue2

    • created VS mounted 发起异步请求
    • vue2-2
  • Vue3

    • Vite + Vue3 修改 element-plus 源码
    • Vue v-if 与 v-show
    • Vue3 ref 获取组件
    • Vue3 路由传参
    • 父子组件与组件里 Hooks 加载顺序
    • 第三方组件传入参数TS提示
    • Vue3 Props 在 Hooks 中的响应性处理
    • Vue Router 的两种历史模式及部署配置详解
    • 在Vue 3项目中顺利集成Tailwind CSS的完整指南
    • Vue 3 深度选择器:deep()完全指南
  • Electron

    • 快速构建 electron + vue3 项目
  • TS

    • TS 泛型
    • 记录模板使用断言的问题
    • type 与 interface
  • WebPack

    • Webpack 介绍
  • Vite

    • Vite CLI 常见命令
    • vite 与 webpack 比较
  • 项目工程

    • 前端代码风格
    • Vue3 项目规范
    • npm 镜像问题
    • 包管理工具
    • 使用 engines 限制开发环境依赖
    • 打包与shell交互指定模式
    • 使用 pnpm 构建 Monorepo 实战指南
    • pnpm 修改依赖源码打包报错
  • 记录一下小程序
  • 控制浏览器正确保存网站账号密码的技巧

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. 总结

  1. 尽量避免直接在路由中传递响应式对象,如果要传递,请先转换成普通对象(toRaw 或 JSON.parse(JSON.stringify()))。

  2. 若传递过去后还要保持响应式,可在目标组件中手动创建新 ref/reactive 并赋值。

  3. 选择更合适的参数方式(query / params / state),title、简易 ID 等基础数据可直接用 query 或 params,大对象或内部结构较复杂的数据可考虑使用 state,并确保序列化后再传递。

最后更新时间:
贡献者: 何风顺
上一页
Vue3 ref 获取组件
下一页
父子组件与组件里 Hooks 加载顺序