目录
  1. 1. 基本步骤
    1. 1.1. 安装
    2. 1.2. 导入路由对象
    3. 1.3. 创建路由实例
    4. 1.4. 挂载路由
  2. 2. 使用
    1. 2.1. <router-link>及属性
    2. 2.2. <router-view>及命名视图
    3. 2.3. 命名路由
    4. 2.4. 路由嵌套
    5. 2.5. $router 路由对象
    6. 2.6. $route 路由信息
    7. 2.7. 路由懒加载
    8. 2.8. 路由守卫
      1. 2.8.1. router.beforeEach 全局前置守卫
      2. 2.8.2. router.afterEach 全局后置钩子
      3. 2.8.3. 路由独享的守卫
      4. 2.8.4. 组件内的守卫
    9. 2.9. keep-alive 与路由
前端路由 vue-router 使用总结 - 前端随笔

基本步骤

  1. 安装vue-router
  2. 导入路由对象,Vue.use(VueRouter)
  3. 创建路由实例,并配置路由映射关系(路由组件映射关系)
  4. Vue实例挂载路由实例

安装

生产依赖

1
$ npm install vue-router --save

导入路由对象

1
2
3
4
5
// ./router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

创建路由实例

  1. 引入路由组件
  2. 创建路由对象实例,并设置路由映射规则
1
2
3
4
5
6
7
8
9
10
11
// ./router/index.js
import Home from '../components/Home' // 路由组件
import About from '../components/About' // 路由组件

export default new VueRouter({
routes:[
{ path: '/', redirect: '/home' },
{ path: '/home', component: Home },
{ path: '/about', component: About }
]
})

路由对象实例属性:

  • routes: 路由映射规则;
  • mode: 路由模式,可设置history,默认hash;
  • linkActiveClass: 整体设置router-link选中样式,默认router-link-active;

挂载路由

1
2
3
4
5
6
7
// ./main.js
import router from './router'

new Vue({
el: '#app',
router
})

使用

利用 <router-link> 跳转路由

属性:

  • to: 路由路径;
  • tag: 渲染标签,默认渲染成<a>标签;
  • active-class: 选中样式,默认router-link-active;
  • replace: 路由跳转设置成替换(不可返回/前进),默认为push(有路径记录);
1
<router-link to="/home" tag="li" replace active-class="li-active">首页</router-link>

<router-view>及命名视图

<router-view> 路由出口

当同级有多个视图时,可使用命名视图。如果 router-view 没有设置名字,那么默认为 default

1
2
3
<router-view></router-view>
<router-view name="a"></router-view>
<router-view name="b"></router-view>

而多视图时路由规则配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
const router = new VueRouter({
routes: [
{
path: '/',
components: {
default: Foo,
a: Bar,
b: Baz
}
}
]
})

命名路由

设置路由规则时,可以设置一个名称来标示某个路由,在使用动态路由时传递参数时更加方便。可以在创建 Router 实例的时候,在 routes 配置中给某个路由设置名称。

1
2
3
4
5
6
7
8
9
const router = new VueRouter({
routes: [
{
path: '/user/:userId',
name: 'user',
component: User
}
]
})

<router-link> 链接命名路由则需要给 to 属性传入一个对象:

1
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>

通过代码跳转路由 $router.push() 时同样要传入一个对象:

1
router.push({ name: 'user', params: { userId: 123 }})

路由嵌套

  1. 路由对象中规则对应组件添加children属性,配置子路由;
  2. 对应组件中添加<router-view>,及路由跳转设置;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// ./router/index.js
import Home from '../components/Home'
import Homenews from '../components/Homenews'
import Homemsg from '../components/Homemsg'
import About from '../components/About'

export default new VueRouter({
routes:[
{ path: '/', redirect: '/home' },
{ path: '/home', component: Home, children: [
{ path: 'news', component: Homenews },
{ path: 'msg', component: Homemsg }
]},
{ path: '/about', component: About }
]
})
1
2
3
4
5
6
7
8
9
<!-- ./components/Home.vue -->

<template>
<div>
<router-link to="/home/news">新闻</router-link>
<router-link to="/home/msg">信息</router-link>
<router-view/>
</div>
</template>

$router 路由对象

  • $router.push(): 路径跳转;
  • $router.replace(): 路径替换;
1
2
3
4
5
6
7
8
9
export default {
name: 'App',
methods: {
btnClick() {
this.$router.push('/about'); // 路径跳转
this.$router.replace('/about'); // 路径替换
}
}
}

传递查询信息,$router.push() 中传入一个对象,并设置 query 对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
export default {
name: 'App',
data() {
return {
userId: '1111',
userName: 'Vincent'
}
},
methods: {
btnClick() {
this.$router.push({
path: '/profile',
query: {
id: this.userId,
userName: this.userName
}
});
}
}
}

$route 路由信息

  • $route.params.xxx: 动态路由参数;
  • $route.query.xxx: 路由查询;

基本设置

1
2
3
4
5
6
7
8
9
10
// ./router/index.js
import User from '../components/User'
import Profile from '../components/Profile'

export default new VueRouter({
routes: [
{ path: '/user/:id', component: User }, // 动态路由
{ path: '/profile', component: Profile }
]
})
1
2
3
4
5
6
7
8
9
10
11
<!-- ./components/App.vue -->
<template>
<div>
<!-- 动态路由 -->
<router-link :to="'/user/'+userId"></router-link>
<!-- 路由查询 -->
<router-link :to="{path: 'profile', query: {id: userID, name: userName} }">

<router-view/>
</div>
</template>

获取动态路由参数

1
2
3
4
5
6
7
<!-- ./components/User.vue -->

<template>
<div>
<p>{{ $route.params.id }}</p>
</div>
</template>

获取路由查询信息

1
2
3
4
5
6
7
8
<!-- ./components/Profile.vue -->

<template>
<div>
<p>{{ $route.query.id }}</p>
<p>{{ $route.query.name }}</p>
</div>
</template>

路由懒加载

方式一:结合Vue的异步组件和Webpack的代码分析;

1
2
3
4
5
6
const Home = resolve => {
require.ensure(['../components/Home.vue'], () => {
resolve(require('../components/Home.vue'));
}
})
}

方式二:AMD写法

1
const Home = resolve => require(['../components/Home.vue'], resolve);

方式三:ES6中更加简便的Vue异步组件和Webpack的代码分割写法(推荐且常用)

1
2
// ./router/index.js
const Home = () => import('../components/Home.vue');

路由守卫

完整导航流程

  1. 导航被触发。
  2. 在失活的组件里调用离开守卫。
  3. 调用全局的 beforeEach 守卫。
  4. 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
  5. 在路由配置里调用 beforeEnter
  6. 解析异步路由组件。
  7. 在被激活的组件里调用 beforeRouteEnter
  8. 调用全局的 beforeResolve 守卫 (2.5+)。
  9. 导航被确认。
  10. 调用全局的 afterEach 钩子。
  11. 触发 DOM 更新。
  12. 用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。

router.beforeEach 全局前置守卫

1
2
3
4
5
const router = new VueRouter({ ... })

router.beforeEach((to, from, next) => {
// ...
})

每个守卫方法接收三个参数:

  • to: Route: 即将要进入的目标 路由对象

  • from: Route: 当前导航正要离开的路由

  • next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。

    • next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。

    • next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。

    • next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: truename: 'home' 之类的选项以及任何用在 router-linkto prop 或 router.push 中的选项。

    • next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。

确保要调用 next 方法,否则钩子就不会被 resolved。


router.afterEach 全局后置钩子

和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身:

1
2
3
router.afterEach((to, from) => {
// ...
})

路由独享的守卫

可以在路由配置上直接定义 beforeEnter 守卫:

1
2
3
4
5
6
7
8
9
10
11
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})

组件内的守卫

可以在路由组件内直接定义以下路由导航守卫:

  • beforeRouteEnter
  • beforeRouteUpdate (2.2 新增)
  • beforeRouteLeave
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}

keep-alive 与路由

<router-view><keep-alive> 包裹起来,可保持缓存组件,不会每次路由跳转时都销毁组件。

注意:缓存的同时 createddestroyed 等生命周期函数在二次进入组件时都不会被调用。但可以使用 activateddeactivated 钩子函数来替代,这两个钩子函数也只能在 keep-alive 组件中才能使用。

1
2
3
4
5
6
7
<template>
<div>
<keep-alive exclude="User">
<router-view/>
</keep-alive>
</div>
</template>

keep-alive 标签属性:

  • include - 字符串或正则表达式。只有名称匹配的组件会被缓存。2.1.0 新增
  • exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。2.1.0 新增
  • max - 数字。最多可以缓存多少组件实例。2.5.0 新增
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- 逗号分隔字符串 -->
<keep-alive include="a,b">
<component :is="view"></component>
</keep-alive>

<!-- 正则表达式 (使用 `v-bind`) -->
<keep-alive :include="/a|b/">
<component :is="view"></component>
</keep-alive>

<!-- 数组 (使用 `v-bind`) -->
<keep-alive :include="['a', 'b']">
<component :is="view"></component>
</keep-alive>

includeexclude 匹配首先检查组件自身的 name 选项,如果 name 选项不可用,则匹配它的局部注册名称 (父组件 components 选项的键值)。匿名组件不能被匹配。


参考文献:

文章作者: Vincent F0ng
文章链接: https://vincef0ng.cn/post/vue-router/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Vincent F0ng

评论(支持Markdown)