动态路由匹配

如何将多路径映射至同一组件?如何在该组件下监听路径的变化?

如何将多路径映射至同一视图?

在某些时候,我们需要将某些具有相同特征的路由(routes)映射至同一视图(component)下。例如我们有一个 User 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。那么,我们可以在 vue-router 的路由路径中使用“动态路径参数”(dynamic segment)来达到这个效果:

const user = { template: '<div>User</div>' };
const router = new VueRouter({
    routes: [{
        path: '/user:id', // 现在,像 '/user/foo' 和 '/user/bar' 都能匹配到,会使用同一个 user 组件渲染
        component: user,
    }],
});

一个“路径参数”使用冒号 : 标记。当匹配到一个路由时,参数值会被设置到 this.$route.params,可以在每个组件内访问到。同样的,也可以在一个路由中设置多段“路径参数”,对应的值都会设置到 $route.params 中。例如:

如何监听/响应动态参数的变化?

当我们使用了动态参数来使多个路径都映射至同一组件时,根据文档的描述,会将之前的组件进行复用,即当路由从 /user/foo 切换至 /user/bar 时,会将复用之前的组件,而不是销毁再创建,这样显得更加高效。但是组件的复用会导致组件的钩子函数不会被调用

要监听/响应动态参数的变化,有两种方法:

在组件中对 $route 进行 watch(监听):

export default {
  watch: {
    '$route'(to, from) {
      // do something...
      // console.log(this.$toute.params)
    }
  },
}

使用 beforeRouteUpdate 钩子函数:

export default {
  beforeRouteUpdate(to, from, next) {
    // do something...
    // console.log(this.$toute.params)
    next(); // do not forget to call next()
  }
}

beforeRouteUpdate 钩子函数仅对因动态参数发生的路由变化有效,函数中可以使用 this

更复杂的路由匹配

提到更复杂、更高级的匹配,必然要涉及正则表达式。Vue Router 使用 path-to-regexp 作为高级路由匹配引擎,可参考官方文档使用。

路由匹配的优先级

有时候,同一个路径可以匹配多个路由,此时,匹配的优先级就按照路由的定义顺序:谁先定义的,谁的优先级就最高。

官网上的解释过于简单,我从网上看到的一个采坑经历如下,放在这里谨防自己在以后的开发中碰到,点此跳转至原文

问题代码如下:

import VueRouter from 'vue-router';
Vue.use(VueRouter);

const routes = [
  {
    path: '/app/:id',
  },
  {
    path: '/app/page1',
    meta: {
      title: 'page1',
    },
  },
  {
    path: '/app/page2',
    meta: {
      title: 'page2',
    },
  },
];

const router = new VueRouter({
  routes
});

router.beforeEach((to, from, next) => {
  document.title = to.meta.title;
  next();
});

出现的问题是:meta.title 一直为 undefined。为什么会出现这种错误呢?依据官方文档上的匹配优先级的解释,因为 /app/:id 将 '/app/page1' 以及 '/app/page2' 都能匹配成功,因此不会对后面的 /app/page1 进行匹配验证。而 /app/:id 没有 meta: { title: 'page1' },因此会导致 meta.title 一直是 undefined

如何修复呢?将特殊的路由模式放在前面,通用的路由模式放后面即可:

const routes = [
  {
    path: '/app/page1',
    meta: {
      title: 'page1',
    },
  },
  {
    path: '/app/page2',
    meta: {
      title: 'page2',
    },
  },
  {
    path: '/app/:id',
  },
];

或者更加简洁的:

const routes = [
  {
    path: '/app/:id',
  },
];

const router = new VueRouter({
  routes
});

router.beforeEach((to, from, next) => {
  document.title = to.params.id; // 动态参数键值对在 params 字段中
  next();
});

Last updated