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
有两种导航模式:
hash
history
注意到地址栏中出现了
#
,表示此时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)
:进入该组件时触发,在其中不能获得组件实例this
beforeRouteUpdate(to, from, next)
:路由发生改变,且组件被复用时触发,即动态路由beforeRouteLeave(to, from, next)
:离开当前组件对应的路由时触发
组件缓存
当我们在不同的路由之间进行切换时,路由对应的组件会被销毁与重建(动态路由组件可能会被复用),频繁的创建组件可能会对性能带来影响,我们可以组件加上缓存,当再次来到某个路由时,不是重新创建一个组件,而是使用缓存的组件。
为 <router-view>
的外层加上 <keep-alive>
可以将组件进行缓存,为了验证组件是否有缓存,我们在 created
钩子函数中打印消息,如果在多次切换路由时只打印一次消息,说明组件被缓存了,并没有重新创建组件
// Index.vue |
// About.vue |
// App.vue |
const routes = [{ |
当我们多次改变路由时,组件只被创建了一次,可见组件被缓存了。