欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

在Vue中,如何在vue-router的不同路由之间传递对象参数

最编程 2024-08-01 19:32:00
...

vue-router 路由间的参数传递

vue-router 是一款配合vue使用的路由组件。最近项目上遇到了一些历史遗留的问题代码,在解决问题的同时,决定梳理一下路由传参的各个方式。

vue-router常见的传参方式有以下几种:

带参数的动态路由匹配

官方文档:带参数的动态路由匹配 | Vue Router (vuejs.org)

简单来说,就是使用页面的路径来传递参数。

比如定义路由:

// 这些都会传递给 `createRouter`
const routes = [
  // 动态字段以冒号开始,User 是一个 vue 组件
  { 
    path: '/users/:username', 
    name: 'UserHomePage'
   	component: User 
  },
]

就可以通过如下方式将用户id传递给目标路由:

router.push({
  name:'UserHomePage',
  params: { username:"zhangsan" }
})

路由跳转成功后,地址栏的路径会变成 /users/zhangsan,在目标路由页面可以通过如下方式获取参数:

let { username } = route.params; 

需要注意的是,使用此种方法建议要使用 name 来push到目标路由,因为如果你指定了 path 参数,那么 params 里对应的字段将会被忽略,不会展现在URL上。

query 传参数

通过指定 query 参数来将数据传递到下一个页面:

router.push({
  name:'UserHomePage',
  params: { username:"zhangsan" }
  query: { showAvatar: "true" }
})

这个方式,是使用 URL 中的 search 字段来传递参数,路由跳转成功后地址栏的路径会变成 /users/zhangsan?showAvatar=true,在目标路由页面可以通过如下方式获取参数:

let { username } = route.query; 

这种方式,和第一种其实是可以混合使用的。他们并不冲突

以上两种方式,都是通过路由地址来传递参数,他们有一些很明显的缺点:

  • query方式 只支持字符串或者字符串数组,传递对象需要进行JSON序列化
  • 路由间的参数会以明文的方式暴露在URL中

同样的,从另一方面考虑,也有它的优势

  • 刷新页面不会丢失参数
  • 路径参数让url 路径看起来更加有可读性,结构分明

错误的使用 params 传参

除了1、2 两种,还有第三种不规范的使用方式,它解决了一些问题,但引入了更多的问题。

在开发中,有时候由于一些需求,不得不在两个路由间传递大量结构化数据。虽然我们可以通过将数据序列化成 JSON 字符串后通过上面的两种方式传递,但有时候我们并不希望这些杂乱无章不可阅读的数据出现在URL上,或者,出于某些因素,不方便将这些数据展示在URL上。而且在目标路由获取到JSON字符串后还需要反序列化成对象才能使用。

此时,程序员们充分发挥了 “ 又不是不能用 ” 的编程精神,开始不规范的使用第一种 通过 params 参数的传参数方式。

⚠️以下是不规范的做法

在定义路由的时候,不定义参数匹配字段,而是像 普通固定路由那样定义路由:

const routes = [
  // User 是一个 vue 组件
  { 
    path: '/users/profile', 
  	name:'UserHomePage', // name 字段可有可无,这不重要
   	component: User 
  },
]

路由跳转时依然正常的使用params字段传参数:

router.push({
  name:'UserHomePage',
  params: { username:"zhangsan" }
})

在目标路由依然使用同样正常的方式获取参数。

这样就达到了我们上面说的两个目的:

  • 由于路由的path没有定义动态匹配字段。所以 URL上不会展示 params 字段里的任何参数。
  • 目标路由通过 route.params 可以获取到 JSON 对象,而不是字符串,不需要进行序列化和反序列化到操作。

看似完美解决了问题,但这样做有两个致命的缺陷,

  • 一旦刷新页面,参数将丢失。
  • 一旦跳转到其他页面,然后用户点击浏览器的返回按钮,路由重新加载,参数也将丢失。

也许通过一些处理,比如将参数在 local storage 等存储方式上做一些缓存可以解决这些问题,但这无疑引入了更多的复杂逻辑和不规范的操作。

而且,在 vue-router 4.1.4中 ,官方为了规范使用,已经移除 了对这一方式的支持,未在path中匹配的参数字段将被移除,详情见更新日志:router/CHANGELOG.md at main · vuejs/router (github.com)

完美的解决方案:使用 window.history.state

上面不规范的使用方式主要为了实现以下几个目标:

  • URL不展示参数
  • 参数不进行序列化和反序列化

同时还要保证:

  • 刷新和回退等操作不会导致参数丢失

在官方的 4.1.4 更新日志 中,推荐了几种替换上面不规范使用方式。

我更喜欢其中的 window.history.state 实现方式。

只需在 push 时 将参数传递到 state 字段中,vue-router 就会将参数存到 window.history.state 中。

使用方式如下:

/// 路由的定义与普通方式无异

// 传参
router.push({
  name:'UserHomePage',
  state: { username:"zhangsan" }
})

// 获取参数
let username = window.history.state.username;

即使是刷新或者前进后退,参数也不会丢失,而且URL路径中也不会显示参数,同时也不需要对参数进行序列化。支持所有能序列化成JSON的对象。唯一的限制是大小不能超过2MiB。

具体请参考window.history.state的MDN文档:

  • state - Web API 接口参考 | MDN (mozilla.org)
  • History.pushState() - Web API 接口参考 | MDN (mozilla.org)

至此,我们完美实现了上述几个目标。

推荐阅读