Code前端首页关于Code前端联系我们

一、先搞懂Vue Router里的路由历史是啥?

terry 6小时前 阅读数 9 #Vue

做Vue项目时,不少开发者会碰到这样的需求:想知道用户之前浏览过哪些页面、控制页面的前进后退,或者做个类似“返回上一级”的自定义按钮……这时候就需要和「路由历史」打交道,那在Vue里到底怎么获取路由历史?不同场景下该咋操作?今天咱们一步步拆解清楚。

Vue Router实现单页应用(SPA)的路由跳转,核心依赖“历史记录管理”,简单说,路由历史就是用户在SPA里切换页面时,所有访问过的路由地址组成的“导航轨迹”。

但这里得区分路由模式的影响:Vue Router支持两种主流模式——hash模式和HTML5 history模式。

  • hash模式:URL里带(比如http://xxx.com/#/home),靠URL的哈希值变化来模拟路由跳转,底层用window.onhashchange监听。
  • HTML5 history模式:URL更“干净”(比如http://xxx.com/home),依赖HTML5的history.pushStatehistory.replaceStatepopstate事件来管理路由。

不管哪种模式,Vue Router内部都有个history对象,用来维护路由的前进、后退逻辑,这个history对象里存着路由变化的关键信息,比如当前路由、历史记录栈等。

获取路由历史的常用方法有哪些?

直接访问router实例的history属性

在Vue组件里(比如页面组件、路由守卫里),可以通过this.$router.history拿到路由的历史管理对象,不过得注意,不同路由模式下,这个history对象的结构略有差异:

  • 如果是hash模式,this.$router.history对应的是HashHistory类的实例,里面有current(当前路由信息)、stack(历史记录栈,存着曾经访问过的路由对象)等属性。
  • 如果是history模式,对应的是HTML5History类的实例,同样有currentstack,还和浏览器原生historyAPI联动更紧密。

举个简单例子,在组件方法里打印路由历史:

export default {
  methods: {
    logRouterHistory() {
      const history = this.$router.history;
      console.log('当前路由:', history.current); 
      console.log('历史记录栈:', history.stack); 
    }
  }
}

不过stack不是“无限制”保存的,它和浏览器的会话历史逻辑有关,主要记录关键的路由跳转节点。

用导航守卫追踪路由变化

Vue Router的导航守卫(比如beforeEachbeforeEnterafterEach)能捕获“路由即将变化”或“路由已经变化”的时机,在守卫里,我们能拿到to(即将进入的目标路由)和from(当前离开的路由),通过记录这两个参数,就能自己维护一份“路由访问历史”。

比如在全局守卫里存历史到Vuex:

// router/index.js
import router from './router'
import store from './store'
router.beforeEach((to, from, next) => {
  // 把离开的路由(from)加入历史记录
  store.commit('ADD_ROUTE_HISTORY', from);
  next();
});

然后在Vuex的state里维护一个数组routeHistory,这样就能随时拿到用户访问过的路由列表,这种方式的好处是能完全自定义历史记录的存储规则(比如只存某些页面、去重等),适合做复杂的导航分析。

结合浏览器原生history API辅助

因为Vue Router的history模式本身基于浏览器historyAPI,所以也能通过原生方法补充信息,比如想知道“当前路由在浏览器历史中的位置”,可以用window.history.length(但注意,SPA的路由跳转和多页面的history长度逻辑有差异,SPA里history.length可能不会像多页面那样逐次增加,因为很多是pushState操作)。

监听popstate事件(仅history模式有效)也能感知用户点击浏览器“前进/后退”按钮的行为:

window.addEventListener('popstate', () => {
  console.log('浏览器前进/后退触发,当前路由:', this.$router.currentRoute);
});

不过这种方式更偏向“被动监听”,适合做一些响应式的逻辑,比如页面回退时的弹窗提示。

不同路由模式下,获取历史有啥差异?

hash模式:靠哈希变化“模拟”历史

hash模式下,URL的变化是后面的部分,浏览器不会向服务器发请求,所以路由历史本质是哈希值的变化记录,这时候this.$router.history里的stack保存的是哈希对应的路由对象。

hash模式有个特点:如果用户手动修改URL的哈希部分(比如把#/home改成#/about),也会触发路由变化,这种情况也会被hashHistory捕获到,所以在hash模式下,获取的历史更“灵活”,但受限于哈希的特性,URL美观度稍差。

history模式:和浏览器历史深度绑定

history模式依赖HTML5的historyAPI,路由跳转时用pushStatereplaceState修改URL,这时候浏览器的会话历史(session history)会真实记录这些变化,所以this.$router.history里的信息和浏览器原生history的联动更直接。

history模式有个“坑”:如果用户直接输入URL或者刷新页面,服务器需要配置对应路由的 fallback(比如所有路由都指向index.html),否则会404,这也导致在history模式下,处理路由历史时要更小心“服务端渲染”或“页面刷新”的场景。

获取路由历史能解决哪些实际问题?

自定义面包屑导航

很多后台管理系统需要“面包屑”显示当前位置和层级,这时候就需要知道用户是从哪些页面跳过来的,通过维护路由历史,能动态生成面包屑的层级:

<template>
  <div class="breadcrumb">
    <span v-for="(item, index) in routeHistory" :key="index">
      {{ item.name }} → 
    </span>
    <span>{{ $route.name }}</span>
  </div>
</template>
<script>
export default {
  computed: {
    routeHistory() {
      // 从Vuex或全局变量里拿维护的历史
      return this.$store.state.routeHistory;
    }
  }
}
</script>

自定义返回按钮逻辑

原生的浏览器返回按钮不一定符合业务需求(比如某些页面要拦截返回、或返回时跳转到指定页面),这时候用路由历史就能实现“智能返回”:

methods: {
  goBack() {
    const history = this.$router.history.stack;
    if (history.length > 1) {
      // 有上一级,回退
      this.$router.back();
    } else {
      // 没有上一级,跳转到首页
      this.$router.push('/home');
    }
  }
}

权限控制与历史回溯

比如某些页面需要登录后才能访问,用户从页面A→页面B(需要登录)→登录页→页面B,这时候登录成功后要“回到原本想去的页面B”,这就需要在跳转登录页前,把目标路由(页面B)存到历史记录里,登录后再跳转回去:

// 全局守卫里拦截未登录状态
router.beforeEach((to, from, next) => {
  if (to.meta.requiresAuth && !isLogin()) {
    // 把目标路由存起来
    localStorage.setItem('targetRoute', to.fullPath);
    next('/login');
  } else {
    next();
  }
});
// 登录成功后跳转
methods: {
  handleLogin() {
    // 登录逻辑...
    const target = localStorage.getItem('targetRoute') || '/home';
    this.$router.push(target);
  }
}

页面访问路径埋点统计

产品想统计用户在App内的访问路径,分析用户行为,这时候通过导航守卫记录每个fromto,就能生成用户的“行为轨迹”,再上报到埋点系统:

router.afterEach((to, from) => {
  const trackData = {
    from: from.path,
    to: to.path,
    time: new Date().getTime()
  };
  // 上报埋点
  track(trackData);
});

Vue里获取路由历史不是“一键调用”的简单操作,得结合路由模式、业务场景选择方法:想快速拿到路由内部的历史对象,用`this.$router.history`;想灵活控制历史记录(比如去重、筛选),用导航守卫+状态管理自己存;还要注意不同模式下的差异,避免踩坑,把路由历史用起来,不管是做导航体验优化,还是业务逻辑控制,都能让项目更“聪明”~

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门