Vue 经常被用来构建单页应用,这意味着需要在前端完成在多个视图之间的切换,想要做到这一点,目前的解决方案通过监控路由,根据路由来切换不同的组件,以达到多视图的切换。Vue 官方为我们提供了 Vue Router 来帮助我们实现这个目的。
安装
如果你的项目只是简单的 HTML 页面,那么可以通过 CDN 引入 Vue Router
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>  | 
如果你的项目是一个 npm 项目,那么可以通过 npm 下载 Vue Router
npm install --save vue-router  | 
如果你是通过 vue-cli 创建的项目,则你可通过 vue add 来添加 Vue Router
vue add router  | 
基本使用
首先看入口组件 App.vue
// App.vue  | 
其中牵涉到两个新标签:
<router-link>:默认会被渲染为超链接,当点击时会跳转到to属性指定的地址(路由)<router-view>:根据路由被渲染为特定的组件
接下来我们便要定义路由与组件之间的对应关系。我们将对应写在单独的文件中,以便后期维护,新建文件夹 router,接着在其中新建文件 index.js,在其中定义路由规则
// router/index.js  | 
除开引入组件的代码,首先我们通过 Vue.use(VueRouter) 使用了 VueRouter 插件,接着我们定义的路由与组件的对应关系
| 路由 | 组件 | 
|---|---|
| / | Index | 
| /about | About | 
当路由为 / 时,<router-view> 便会被渲染为 <Index>,当路由为 /about 时,<router-view> 便会被渲染为 <About>。Index.vue 与 About.vue 的内容如下
// Index.vue  | 
// About.vue  | 
内容都十分的简单。接着我们根据路由对应关系创建了 VueRouter 实例 router,并将其导出。在入口文件 main.js 中我们使用该 router
// main.js  | 
当我们点击链接时,地址栏发生变化,且渲染的组件也顺应变化。
VueRouter有两种导航模式:
hashhistory注意到地址栏中出现了
#,表示此时VueRouter是hash模式,地址栏中有#未免不好看,我们可以在创建VueRouter实例时设置mode选项为'history',这时VueRouter便是history模式了
 // router/index.js
const router = new VueRouter({
mode: 'history',
routes
})![]()
这时地址栏上便没有
#了。
有的时候路径的拼写比较复杂,我们可以为路由命名,然后在 to 属性直接指定跳转的路由名称。首先我们在 routes 数组中为路由指定名称
// router/index.js  | 
上面我们通过 name 属性为路由指定了名称,接着我们修改 App.vue 中的导航链接
// App.vue  | 
动态路由匹配
有的时候我们可能需要为组件传递额外的参数,以显示不同的信息,例如 /user/1 显示 id = 1 的用户的信息,/user/2 显示 id = 2 用户的信息,参数通过路由传递,这种路由我们称为动态路由。为了能够接收到参数,我们需要如下定义路由与组件的关系
// router/index.js  | 
注意到动态路由的定义方式 path: '/user/:id',接着我们便可在 User 组件中通过计算属性 $route 来访问到传入的参数,$route 包含如下属性
- fullpath
 - path
 - query
 - params
 - name
 
我们可以通过 $route.params.id 来访问到传入的参数,User.vue 如下
// User.vue  | 
App.vue 的内容如下
// App.vue  | 
有一点需要注意的是,动态路由组件进行切换时会进行组件复用,当路由从 /user/1 变为 /user/2 时并没有重新创建一个新的组件,而是复用了之前的组件。我们可以在 created 方法中打印信息,如果在切换组件时,信息始终只打印了一次,就说明组件只被创建了一次,即组件复用了
// User.vue  | 
组件复用能够带来性能上的优势,但是有的时候我们需要根据路由参数请求数据,因为组件复用的关系,无法通过生命周期钩子请求数据,这时我们可以通过监听器来监听 $watch,当路由发生变化时,我们便发起请求
// User.vue  | 
在组件中直接使用 $route 会使得组件与路由形成高度的耦合,我们希望路由参数能够通过 props 传递给组件。首先需要在路由定义中添加 props 属性,并声明为 true
// router/index.js  | 
接着在 User 组件中对 props 属性进行声明
// User.vue  | 
嵌套路由
假设在 User 组件中还嵌套这一层路由
// User.vue  | 
例如当路由为 /user/:id/foo 时,User 组件中的 <router-view> 渲染为 Foo 组件,当路由为 /user:id/bar 时,渲染为 Bar 组件,当路由为 /user/:id/ 时,渲染为 UserHome 组件。为了达到这个目的,我们需要修改 router/index.js
// router/index.js  | 
注意到我们添加了 children 属性,这是嵌套路由的关键。修改 App.vue 中的跳转链接
// App.vue  | 
编程式的导航
除了通过链接的方式对路由进行更改,我们还可以通过 $router 计算属性更改路由,如
$router.push()$router.replace()
方法的参数可以为字符串,也可以是一个对象
// 字符串  | 
注意:如果提供了
path,params会被忽略,上述例子中的query并不属于这种情况。取而代之的是下面例子的做法,你需要提供路由的name或手写完整的带有参数的path:
 const userId = '123'
router.push({ name: 'user', params: { userId }}) // -> /user/123
router.push({ path: `/user/${userId}` }) // -> /user/123
// 这里的 params 不生效
router.push({ path: '/user', params: { userId }}) // -> /user
$router.replace 接收的参数同 $router.push 相同,唯一不同在于 replace 是替换当前的历史记录,而 push 是添加一条历史记录,它的声明式写法为
<router-link :to="..." replace>  | 
我们还可以通过 $router.go 方法在历史记录之间跳转,该方法接收一个整数 $n$,正数表示向前跳转多少步,负数表示向后跳转多少步
// 在浏览器记录中前进一步,等同于 history.forward()  | 
重定向与别名
重定向就是当你访问路由 /a 时,会自动跳转到路由 /b,如下配置
const routes = [{  | 
重定向也可以指定为一个命名的路由
const routes = [{  | 
假设 /b 是 /a 的别名,当我们访问 /b 时,路由不变,但是会使用 /a 对应的组件,配置如下
const routes = [{  | 
路由守卫
当我们访问一个路由前,我们首先是要对身份进行验证,是否有权限访问这个路由,Vue Router 提供了路由守卫来做这件事情,路由守卫主要用来跳转或者取消的方式来守卫路由。路由守卫分为三种:
- 全局
 - 路由
 - 组件
 
全局前置守卫
可以通过 router.beforeEach 注册一个全局前置守卫
const router = new VueRouter({ ... })  | 
当我们进入一个路由之前会触发此守卫方法,该守卫方法接收三个参数:
to:即将要进入的目标 路由对象from:当前导航正要离开的路由next::next():放行next(false):中断当前导航,如果 URL 改变了,则 URL 会被重置到from路由对应的地址next('/')或者next({ path: '/' }):跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向next传递任意位置对象,且允许设置诸如replace: true、name: 'home'之类的选项next(error):如果传入next的参数是一个Error实例,则导航会被终止且该错误会被传递给router.onError()注册过的回调
router.beforeEach((to, from, next) => {  | 
路由守卫
可以在 routes 中配置路由守卫 beforeEnter
const routes = [{  | 
方法参数同上。
组件内的守卫
也可以直接在组件内部定义路由守卫,有三个:
beforeRouteEnter(to, from, next):进入该组件时触发,在其中不能获得组件实例thisbeforeRouteUpdate(to, from, next):路由发生改变,且组件被复用时触发,即动态路由beforeRouteLeave(to, from, next):离开当前组件对应的路由时触发
组件缓存
当我们在不同的路由之间进行切换时,路由对应的组件会被销毁与重建(动态路由组件可能会被复用),频繁的创建组件可能会对性能带来影响,我们可以组件加上缓存,当再次来到某个路由时,不是重新创建一个组件,而是使用缓存的组件。
为 <router-view> 的外层加上 <keep-alive> 可以将组件进行缓存,为了验证组件是否有缓存,我们在 created 钩子函数中打印消息,如果在多次切换路由时只打印一次消息,说明组件被缓存了,并没有重新创建组件
// Index.vue  | 
// About.vue  | 
// App.vue  | 
const routes = [{  | 
当我们多次改变路由时,组件只被创建了一次,可见组件被缓存了。






