Skip to content

前端导航方案

痛点

在使用 vue-router 进行中后台项目开发时,存在以下痛点

  1. router.push 到一个新页面,需要有返回操作,返回操作可能会有参数携带,并且需要显示上级页面名称及当前页面名称
  2. 多级面包屑的跳转,考虑参数携带
  3. 基于 qiankun 等的微应用的主子跳转、子子跳转,新开 tab 的问题
  4. 出于安全问题浏览器不提供上一个历史记录的接口

相关特性

  • http.referer 只能够获取除了 hash 之外的 url
  • document.referrer 行为与 http.referer 不一致,通过 a 标签跳转可以获取除了 hash 外的完整 url,链接直接点开或者粘贴网址进入都为空字符串,经测试,push 等方法无法改变 document.referrer,但是可以改变 http.referer,不包括 hash
  • history 历史栈,router.pushhistory.pushState 压栈,router.replacehistory.replaceState 修改当前记录,a 标签的跳转不会压栈,vue-router 的重定向也不会压栈
  • back()go(-1),mdn 描述为一致,都等于点击浏览器的回退,但是在一些说法中有人提出 go(-1)会重载页面,back 不会重载
  • back/forward cache。浏览器的前进/回退缓存,可以缓存浏览过的页面快照(包括 JavaScript 堆),使用 bfcache 恢复的重复访问总是比非 bfcache 导航更快

需求描述

在需要返回按钮的页面,获取上一个路由的路由信息及正确的路由返回

方案

方案一

选择采用 sessionStorage,记录上一页的路由信息

全局混入全局前置路由守卫,记录离开页面的路由信息,如

js
router.beforeEach((to, from, next) => {
  sessionStorage.set(to.name, from);
});

同时提供一个返回方法,获取缓存的路由信息并使用 push 返回

优点

  • 自动记录,用户无需关注参数的传递

缺点

  • 仅限两级跳转的简单场景,多级跳转情况下,来源路由会反调

方案二

同样采用 sessionStorage存储路由信息

全局混入 beforeRouteLeave 或者beforeRouteEnter方法,记录离开页面的路由信息

优点

  • 仅在路由表里定义的组件会触发,且可以通过在 meta 里定义属性,做到精准控制对缓存的存取

缺点

  • 同样只适用于两级跳转的简单场景

方案三

document.referrer虽然不能做到获取hash,但是可以判断与当前页是否同源

结合思路二,将上一页的路由信息存在session

在确保项目内合理使用push、replace的情况下,通过referrer判断,如果上一页与当前页同源,直接调用 router.back()router.go(-1)

否则referrer为空字符串,此时replace到缓存信息中的路由,

优点

  • 理论上体验会更好,可以保留浏览器的原生行为,在条件允许的情况下支持back/forward Cache,可以缓存浏览过的页面快照(包括 JavaScript 堆),使用 bfcache 恢复的重复访问总是比非 bfcache 导航更快
  • 能够保证history栈的顺序,无论是使用 push还是 replace 回退,都会导致 history 栈不正确

缺点

  • 浏览器出于安全考虑,无法获取到真正完整的 referrer 地址,因此还是需要配合路由信息缓存

方案四

自行维护一个history

以上两个库主要是针对keep-alive缓存页面,没有去存储上页的路由信息

优点

  • 维护了一个访问历史栈,与浏览器的 back/forward 同步
  • 做了 keep-alive 缓存

缺点

  • 没有存储相关的路由信息,需要修改使用,取栈顶的 path 去路由表中匹配
  • 没有对 back 行为做限制,可以结合 referrer
  • 每次的 push/replace 都会触发对应的缓存存取操作

参考

Released under the MIT License.