Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。

动态路由匹配

我们经常需要把某种模式匹配到的所有路由,全都映射到同一个组件。例如,我们有一个 User 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。那么,我们可以在 vue-router 的路由路径中使用“动态路径参数”(dynamic segment) 来达到这个效果:

const User = {
	template: '<div>User</div>'
}

const router = new VueRouter({
	routes: [
		{
			path: '/user/:id', 
			component: User
		}
	]
})

这样 /user/you/user/me 都将映射到地址为 /user 的路由

像这种“路径参数”使用 标记。当匹配到一个路由时,参数值会被设置到 this.$route.params,可以在每个组件内使用。于是,我们可以更新 User 的模板,输入当前用户的ID:

const User = {
	template: '<div>User {{ $route.params.id }}</div>'
}

可以在一个路由中设置多段“路径参数”,对应的值都会设置到 $route.params 中。例如:

模式匹配路径$route.params
/user/:username/user/Lee{ username: ‘Lee’ }
/user/:username/age/:age_num/user/Lee/age/18{username: ‘Lee’, age: 18}

一些时候,我们可能有这样的需求,一个组件我们可以设置一个参数,但是这个参数它不是必须的:

const router = new VueRouter({
	router: [
		{
			path: '/user/:id',
			component: User
		}
	]
});

按照上面的方式定义 router 路径,如果我们需要跳转到 /user 路径的话,那么我们跳转时必须携带一个id ,就是说我们只能 /user/1 这样才能正确的匹配到 /user/:id 这个路由,那么怎样才能把 :id 变成一个可选参数呢? 很简单,只需要在 :id 后面添加一个 ?

const router = new VueRouter({
	router: [
		{
			path: '/user/:id?',
			component: User
		}
	]
});

这样,我们访问 /user 时就可以根据需求来决定是否需要添加这个id, /user、/user/1

路由参数

我们该如何获取路由跳转时所携带的参数呢?

const router = new VueRouter({
	router: [
		{
			path: '/user/:id?',
			component: User
		}
	]
});
this.$router.push({
	path: '/user',
	query: {
		id: 2
	}
});
// 此时浏览器路径为:/user?id=2
console.log(this.$route.query) // {id:2}

this.$router.push({
	name: 'user',
	params: {
		id: 2
	}
});
// 此时浏览器路径为: /user/2
console.log(this.$route.params) // {id:2}

上述代码中,我们发现了一个问题。有的时候,我们要使用 $router.params 来获取参数,有的时候我们又要使用 $router.query 来获取参数,那么到底怎么区分呢?

实际上,上述代码已经展示了它们的异同: 当我们使用 path 进行路由跳转时,我们是通过 query 添加参数的,而使用 name 进行路由跳转时,我们是通过 params 进行添加参数的。

那么如果 path 通过 params 添加参数是否可行呢?答案是:NO、NO、NO

但是,我们使用 name 进行路由跳转时,却可以使用 query 来添加参数:

const router = new VueRouter({
	router: [
		{
			path: '/user/:id?',
			component: User
		}
	]
});

this.$router.push({
	path: '/user',
	// 使用 path 时,会自动忽略 params 属性
	params: {
		id: 2
	}
});
// 此时浏览器路径为:/user
console.log(this.$route.query) // {}
console.log(this.$route.params) // {id: undefined}


this.$router.push({
	name: 'user',
	// 使用 name 可以同时定义 query、params 两种传参方式
	query: {
		name: 'Lee'
	},
	params: {
		id: 1
	}
});
// 此时浏览器路径为: /user/1?name=Lee
console.log(this.$route.query) // {name: 'Lee'}
console.log(this.$route.params) // {id: 1}

另外,params 中的参数,当用户刷新当前页面时,就会丢失,而 query 则不会

params 传参,相当于http中的 post 请求
query 传参,相当于http中的 get 请求

不是说 params 相当于 post 吗?那么上述示例中的代码,为什么 params 中的 id 会在路径里面显示出来?那是因为在定义路由时,我们通过 /:id 把它具化了,如果把这个参数去掉,我们在浏览器地址栏中是不存在的,但是可以通过 $route.params 取到参数

const router = new VueRouter({
	router: [
		{
			path: '/user/:id?',
			component: User
		}
	]
});

this.$router.push({
	name: 'user',
	params: {
		id: 2,
		name: 'Lee'
	}
});
// 此时浏览器路径为: /user/2
// 我们只能看到已经具化的id,但是看不到name
// 但是我们可以通过 this.$route.params 得到 name
console.log(this.$route.params) // {id: 2, name: 'Lee'}

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

复用组件时,想对路由参数的变化作出响应的话,可以使用 watch 来监听 $route 对象:

const User = {
  template: '...',
  watch: {
    $route(to, from) {
      // 对路由变化作出响应...
    }
  }
}

或者使用 beforeRouteUpdate 导航守卫:

const User = {
  template: '...',
  beforeRouteUpdate (to, from, next) {
    ...
    next() // 一定要记得执行next方法
  }
}

路由元信息

定义路由的时候可以配置 meta 字段:

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      children: [
        {
          path: 'bar',
          component: Bar,
          meta: { requiresAuth: true }
        }
      ]
    }
  ]
})

那么如何访问这个 meta 字段呢?

首先,我们称呼 routes 配置中的每个路由对象为 路由记录。路由记录可以是嵌套的,因此,当一个路由匹配成功后,他可能匹配多个路由记录。

例如,根据上面的路由配置,/foo/bar 这个 URL 将会匹配父路由记录以及子路由记录。

一个路由匹配到的所有路由记录会暴露为 $route 对象 (还有在导航守卫中的路由对象) 的 $route.matched 数组。因此,我们需要遍历 $route.matched 来检查路由记录中的 meta 字段。

下面例子展示在全局导航守卫中检查元字段:

router.beforeEach((to, from, next) => {
  if (to.matched.some(record => record.meta.requiresAuth)) {
    // 如果当前这个路由需要鉴权,则检查是否已登录,如没有登录,则跳转登录
    if (!auth.loggedIn()) {
      next({
        path: '/login',
        query: { redirect: to.fullPath }
      })
    } else {
      next()
    }
  } else {
    next() // 确保一定要调用 next()
  }
})

匹配优先级

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

Logo

前往低代码交流专区

更多推荐