Table of Contents
有这么一种情况,各个不同的页面需要同样的参数,或者进入多层级页面后回跳之前页面时需要带回参数。每个页面手动传递参数是可以的,但是比较麻烦,并且容易丢失。
this.$router.push({ path: 'xxx', qury: { ...this.$route.query } })
如果某个页面忘记写传递参数的代码,bug 就产生了。所以,最好有一种全局统一的处理方法。比如在路由拦截里统一将来源页面(from)的部分参数传递到目标页面(to)。
通过 query 传递
url 里的参数和 query 里的属性是对应的,所以,通过 query 传递通用参数是首选。但是,vue-router 不允许直接修改 query,也不允许直接修改 fullPath(这是只读的)。所以通过 query 自动传递参数的实现比较曲折。
const constantRouterParams = ['aparam', 'bparam'] /** * 路由参数流转 * @param {object} from * @param {object} to * @param {function} next */ routeParamsTransmit(from, to, next) { const sourceParams = from.query const targetParams = to.query // 如果目标路由必要参数不需要改变,直接放行,否则会陷入死循环。因为 next() 是放行,但 next(route) 是中断导航,开始新的跳转。 if ( constantRouterParams.every(key => { return ( sourceParams[key] === undefined || targetParams[key] !== undefined ) })) { next() return } constantRouterParams.map(key => { // 只有源页面参数存在,且目标页面参数为 undefined 的时候才自动传参。这是为了避免目标页面设置的相同 key 的参数时会被覆盖掉。 if (!isEmpty(sourceParams[key]) && (targetParams[key] === undefined)) { targetParams[key] = sourceParams[key] } }) next({ path: to.path, query: targetParams }) }
这样一来就可以将 from 的部分参数自动带给 to。但是,next(route) 的时候会出现重复导航的错误。这需要修复。
// 劫持 router 的 push 方法,因为路由的 beforeEach 里会对 next 方法改造,用于将 from 的部分参数自动带给 to。但是,这样会导致报错:NavigationDuplicated: Avoided redundant navigation to current location const original = Router.prototype.push Router.prototype.push = function push(location) { return original.call(this, location).catch(err => err) }
通过 query 可以实现自动传参,但有潜在风险。比如原本是想 b 页面代替 a 页面,这样处理后会变成 b 页面添加到 a 的历史记录后面(猜测,未验证)。
通过 meta 传递
路由基本都有 meta 属性,一般我们会在里面配置一些页面信息。所以也可以在这里传递页面参数。目的页面通过 this.$route.meta.xxx 取值。写法上和通过 query 差不多,只是参数变成从 meta 到 meta,并且 meta 参数无法反映到 url 中。一旦刷新页面,参数就会丢失。但通过 meta 传递也可以避免路由报错及魔改操作。
全局参数除了路由传递,更常见的是通过 vuex 或者 storage 保存。但这两种方法也都有其缺点。vuex 刷新会丢失。localStorage 会存在数据污染的问题。sessionStorage……也许更适合?嗯……也许下次还是用 sessionStorage 吧,标签生命周期挺符合需求的。