使用Vue Router 也有两三年了。都是零零散散自己写在印象笔记里面,一直没有系统总结过路由的知识点,都是需要用到再去看下文档或者文章。这次把我自己经常用到的路由知识点写下来,以后好自己翻看。
我们平常写的 Vue 项目页面都是由多个组件嵌套成的,所以相应的,路由也需要有嵌套层级。
<router-view>
是渲染组件的出口,我们一般在 id = 'app'里面设置顶层的渲染出口。
<div id="app">
<router-view></router-view>
</div>
routers 是一个数组对象,可以包含多个路由,也就是多个对象。每一个路由对象里面可以设置children 属性,然后children值又是一个数据对象。依次类推,可以一直嵌套下去。
const router = new VueRouter({ routes: [ { path: '/user', component: User, children: [ { path: '/info', component: Info, children: [ { path: '/name', component: Name, // 还可以嵌套 children 数组。 } ] } ] } ] }) 复制代码
要注意,以 / 开头的嵌套路径会被当作根路径。 这让你充分的使用嵌套组件而无须设置嵌套的路径。
以上是Vue Router官网的关于根路由的一个解释。具体的意思:
const router = new VueRouter({ routes: [ { path: '/', children: [ { path: '/user', component: User, children: [ { path: '/info', component: Info, // 还可以嵌套 children 数组。 } ] } ] } ] }) 复制代码
如果我们想要使用动态路由,比如用户详情页。不管是/user_detail/4,还是/user_detail/5。我们都想要匹配到同一个组件。这时候就可以使用动态路由了。
具体方法:
{ path: '/user_detail/:id', component : Detail } 复制代码
但是要注意的是,如果从是/user_detail/4跳转到/user_detail/5,组件会被复用。也就是说,组件的生命周期不会再次创建。
如果想要匹配所有的路径,可以使用 * 来匹配。因为是匹配所有的路径,所以要放在最后。
具体用法:
{ path: '*', component : Error, } 复制代码
然后写一个 Error.vue 的页面既可。
有时候我们想要在一个路由里面,写上多个视图。比如在根路径 / 里面。 我们想要分出三个视图,分别是:顶部视图(个人信息,退出,网页 logo 等),侧边栏视图,主体视图(展示网站主要内容)。这时候同级多视图就派上用场了。
本来我们只需要写一个<router-view></router-view>
,作为渲染出口即可。现在我们想要多个视图,只需要多添加几个<router-view></router-view>
,并给多出来的视图加上命名。
<router-view></router-view> <router-view name="a"></router-view> <router-view name="b"></router-view> 复制代码
注意,在配置里面的 component属性要加上 s 变成components。
然后 default 是匹配没有命名的<router-view></router-view>
。
const router = new VueRouter({ routes: [ { path: '/', components: { default: C, a: A, b: B } } ] }) 复制代码
重定向:当用户访问路由 a 的时候,我们把它定向到 b。
最常见的就是当用户访问根路径的时候,我们把它重定向到首页或是登录页面。
使用 redirect 这个属性来重定向。
{ path: '/a', redirect: '/b' }
{ path: '/a', redirect: { name: 'b' }}
{path: '/a', redirect: to => { // 随机重定向。 if (Math.random() > 0.5) { return { path: '/c'} }else { return '/b' } }, }} 复制代码
顾名思义,给路由起另一个名字。比如一个人朋友叫他张三丰,下属叫他张总,老板叫他小张,其实都是指向同一个人。
/a 的别名是 /b,意味着,当用户访问 /b 时,URL 会保持为 /b,但是路由匹配则为 /a,就像用户访问 /a 一样。
const router = new VueRouter({ routes: [ { path: '/a', component: A, alias: '/b' } ] 复制代码
我们要是在页面上直接导航的话,使用<router-link to="/bar">Go to Bar</router-link>
标签即可,浏览器会把router-link标签渲染成一个 a 标签。
但是我们要是想要在JS 里面通过点击,或者通过特定的条件再跳转。这就需要使用到编程式导航了,编程式导航一共有三种。
这个方法会向浏览器的 history 推入一个新的地址,点击浏览器的后退按钮也可以返回上一步的地址。
这个方法接受的可以是字符串,也可以是对象。
// 字符串 router.push('home') // 对象 router.push({ path: 'home' }) // 命名的路由 router.push({ name: 'user', params: { userId: '123' }}) // 带查询参数,变成 /register?plan=private router.push({ path: 'register', query: { plan: 'private' }}) 复制代码
这个跟router.push很像,不同之处在于,router.push是添加一个新的地址,router.replace是替换当前的地址。
这个方法的接受参数跟router.push一样。既可以是字符串也可以是对象。
这个方法是在浏览器记录前进或者后退几步,接收的参数是一个整数。
不过要是不成功的话,会默默失败,没有提示。比如你要是后退一百步,实际上才你打开这个标签才点击10个链接,也就是在浏览器的 history 栈才有10 个记录,这种情况下最多后退 10步。
this.$router.go(-6); this.$router.go(2); this.$router.go(-4); 复制代码
通过在路由里面所要传递的传参,然后在到达的页面,使用$route.params,接受传递过来的参数。
路由写法:{ path: '/user/:id', component: User }
接收写法: this.$route.params.id
上面这种方法耦合性很高,所以可以使用 props 解耦。
路由写法:{ path: '/user/:id', props: true, component: User }
接收写法:
props:['id'], mounted(){ console.log(this.id) }, 复制代码
这样就会挂载当前组件的 data 对象上面。
这个 params 是和 name 配合使用的。跳转过去之后路径不会带上参数。
编程式路由写法:router.push({ name: 'user', params: { userId: '123' }})
接收写法:this.$route.params.id
这个 query 是和 path 配合使用的,跳转过去之后路径会带上参数变成 /search?id=1 般使用在查询方面。
编程式路由写法:router.push({ path: 'search', query: { id: '1' }})
接收写法::this.$route.query.id
当路由进行需要进行导航的时候,我们可以通过路由守卫的方式,来进行路由的跳转和和取消跳转。
路由守卫有三种,一种是全局的守卫,一种是路由的守卫,一种是组件的守卫。
全局守卫一般用来验证是否已经登陆。如果登陆,就进行,没有登录就跳转到登录页面。
router.beforeEach((to, from, next) => { /* 必须调用 `next` 常用这个 */ }) router.beforeResolve((to, from, next) => { /* 必须调用 `next` */ }) router.afterEach((to, from) => { /* 这是全局后置钩子,不会接受 next 函数,也不改变导航 */ }) 复制代码
跟全局路由一样,只不过是针对单个路由,来进行设置。
routes: [ { path: '/foo', component: Foo, beforeEnter: (to, from, next) => { // ... } } ] 复制代码
组件的守卫,一共有三个;
beforeRouteEnter (to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `this` // 因为当守卫执行前,组件实例还没被创建 }, beforeRouteUpdate (to, from, next) { // 在当前路由改变,但是该组件被复用时调用 // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。 // 可以访问组件实例 `this` }, beforeRouteLeave (to, from, next) { // 导航离开该组件的对应路由时调用 // 可以访问组件实例 `this` } 复制代码
之所以要用路由懒加载,是因为如果把所有的路由都打包,会导致首屏加载时间过长,导致白屏。
Vue路由懒加载有两种方式:
Vue 官方,使用 import 方式。
阮一峰ES6 文档里面介绍 import :
import()函数可以用在任何地方,不仅仅是模块,非模块的脚本也可以使用。它是运行时执行,也就是说,什么时候运行到这一句,就会加载指定的模块。
const Foo = () => import('./Foo.vue')
然后正常使用组件即可。
const router = new VueRouter({ routes: [ { path: '/foo', component: Foo } ] }) 复制代码
使用 Vue 异步组件。
直接在组件里面写,一行代码可以搞定。
component:resolve=>(require(["@/components/Foo"],resolve))
1.网上还有一种方法是webpack 的require.ensure()方式,实现懒加载。 2.使用懒加载后,需要修改build 的设置。在build下面的webpack.prod.conf.js 找到 publicPath:"./"
vue路由传参
Vue-Router 官方文档