3.vue-router动态路由匹配/user/:id

2,613 阅读2分钟

1. 动态路由匹配/user/:username/post/:post_id

我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件。

  • 例如,有一个 User 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。那么,我们可以在 vue-router 的路由路径中使用“动态路径参数”(dynamic segment) 来达到这个效果:
const User = {
  template: '<div>User</div>'
}

const router = new VueRouter({
  routes: [
    // 动态路径参数 以冒号开头
    { path: '/user/:id', component: User }
  ]
})

现在,像 /user/foo 和 /user/bar 都将映射到相同的路由。

1.gif

  • 一个“路径参数”使用冒号 : 标记。当匹配到一个路由时,参数值会被设置到 this.$route.params,可以在每个组件内使用。于是,我们可以更新 User 的模板,输出当前用户的 ID:
const User = {
  // template: '<div>User {{ $route.params.id }}</div>'
  template: "<div>{{ $route.params}}</div>"
}

1.gif

  • 可以在一个路由中设置多段“路径参数”,对应的值都会设置到 $route.params 中。例如:
模式匹配路径$route.params
/user/:username/user/evan{ username: 'evan' }
/user/:username/post/:post_id/user/evan/post/123{ username: 'evan', post_id: '123' }

1.gif

  • 除了 $route.params 外,$route 对象还提供了其它有用的信息,例如,$route.query (如果 URL 中有查询参数)、$route.hash 等等。更多查看 API 文档 。

image.png

2. 响应动态路由参数/user/:id的变化

当使用动态路由参数/user/:id时,例如从 /user/foo 导航到 /user/bar原来的组件实例会被复用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会再被调用

  • 复用组件时,想对路由参数的变化作出响应的话,可以简单地 watch (监测变化) $route 对象:
const User = {
  template: "<div>{{ $route.params}}</div>",
  created() {
      console.log("组件复用,created只调用一次");
    },
    watch: {
      $route(to, from) {
        // 对路由变化作出响应...
        console.log("to", to);
        console.log("from", from);
      }
    }
}

1.gif

const User = {
  template: "<div>{{ $route.params}}</div>",
  beforeRouteUpdate(to, from, next) {
      // react to route changes...
      // don't forget to call next()
      // 在当前路由改变,但是该组件被复用时调用
      // 举例来说,对于一个带有动态参数的路径 /user/:id,在 /user/evan 和 /user/lxl 之间跳转的时候,
      // 由于会渲染同样的 User 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
      // 可以访问组件实例 `this`
      console.log("to", to);
      console.log("from", from);
      console.log("next", next);
      next();
  }
}

1.gif

3. 通配符 (*)捕获所有路由或 404 Not found 路由

常规参数只会匹配被 / 分隔的 URL 片段中的字符。如果想匹配任意路径,我们可以使用通配符 (*):

{
  // 会匹配所有路径
  path: '*'
}
{
  // 会匹配以 `/user-` 开头的任意路径
  path: '/user-*'
}
  • 当使用通配符路由时,含有通配符 (*)的路由应该放在最后。
  • 路由 { path: '*' } 通常用于客户端 404 错误。
  • 如果使用了History 模式,请确保正确配置你的服务器

当使用一个通配符 (*)时,$route.params 内会自动添加一个名为 pathMatch 参数。它包含了 URL 通过通配符 (*)被匹配的部分:

// { path: "/user-*", component: User },
// { path: "*", component: User },
// 给出一个路由 { path: '/user-*' }
this.$router.push('/user-admin')
this.$route.params.pathMatch // 'admin'
// 给出一个路由 { path: '*' }
this.$router.push('/non-existing')
this.$route.params.pathMatch // '/non-existing'

1.gif

4. vue-router高级匹配模式

vue-router 使用 path-to-regexp作为路径匹配引擎,所以支持很多高级的匹配模式,例如:可选的动态路径参数、匹配零个或多个、一个或多个,甚至是自定义正则匹配。查看文档学习高阶的路径匹配。

一个例子展示 vue-router 怎么使用这类匹配。

1.gif

import Vue from "vue";
import VueRouter from "vue-router";

Vue.use(VueRouter);

// The matching uses path-to-regexp, which is the matching engine used
// by express as well, so the same matching rules apply.
// For detailed rules, see https://github.com/pillarjs/path-to-regexp
const router = new VueRouter({
  mode: "history",
  base: __dirname,
  routes: [
    { path: "/" },
    // params are denoted with a colon ":"
    { path: "/params/:foo/:bar" },
    // a param can be made optional by adding "?"
    { path: "/optional-params/:foo?" },
    // a param can be followed by a regex pattern in parens
    // this route will only be matched if :id is all numbers
    { path: "/params-with-regex/:id(\\d+)" },
    // asterisk can match anything
    { path: "/asterisk/*" },
    // make part of the path optional by wrapping with parens and add "?"
    { path: "/optional-group/(foo/)?bar" }
  ]
});

new Vue({
  router,
  template: `
    <div id="app">
      <h1>Route Matching</h1>
      <ul>
        <li><router-link to="/">/</router-link></li>
        <li><router-link to="/params/foo/bar">/params/foo/bar</router-link></li>
        <li><router-link to="/optional-params">/optional-params</router-link></li>
        <li><router-link to="/optional-params/foo">/optional-params/foo</router-link></li>
        <li><router-link to="/params-with-regex/123">/params-with-regex/123</router-link></li>
        <li><router-link to="/params-with-regex/abc">/params-with-regex/abc</router-link></li>
        <li><router-link to="/asterisk/foo">/asterisk/foo</router-link></li>
        <li><router-link to="/asterisk/foo/bar">/asterisk/foo/bar</router-link></li>
        <li><router-link to="/optional-group/bar">/optional-group/bar</router-link></li>
        <li><router-link to="/optional-group/foo/bar">/optional-group/foo/bar</router-link></li>
      </ul>
      <p>Route context</p>
      <pre>{{ JSON.stringify($route, null, 2) }}</pre>
    </div>
  `
}).$mount("#app");

5.优先匹配先定义的路由

有时候,同一个路径可以匹配多个路由,此时,匹配的优先级就按照路由的定义顺序:路由定义得越早,优先级就越高,按照先定义的路由组件进行渲染

{ path: "/user", component: Bar }, //渲染先定义的路由
{ path: "/user", component: User }