vue学习笔记之router2.0

最近一直在搞ssr的东西,也没来的及看看router2.0和vuex2.0到底带来了什么变化,今天来具体尝试一下,边学边练,我们会实现具有以下功能的例子

  • 还有两级以上的嵌套路由
  • 控制路由跳转规则
  • 实现懒加载

1.用router整合组件

首先,我们使用router配置最基本的组件和路由的映射,告诉vue-router在哪里渲染他们,来实现我们单页面应用的第一步。

实现基本的映射很简单,只需要进行以下几步即可:

1.1 定义导航及路由渲染区域

  • 通过router-link组件来进行导航,类似我们平常使用的超链接
  • 通过router-view来配置路由的渲染区域

首先我们使用vue-cli建立基本的项目工程,并安装vue-router

1
2
3
4
5
$ vue-init webpack test
$ cd test
$ npm install
$ npm install vue-router --save
$ npm run dev

a.配置导航组件:

在这里我们定义一个Header组件,来进行页面整体内容的导航,通过router-link设置跳转到Foo,Bar两个组件的内容,并做一些基本的UI设定。

1
2
3
4
5
6
7
8
<template>
<header id="main-header">
<!-- 通过'to'传入跳转路由 -->
<!-- 默认被渲染为<a>标签 -->
<router-link to="/foo" class="header-item">Foo</router-link>
<router-link to="/bar" class="header-item">Bar</router-link>
</header>
</template>

b.整合匹配视图:
通过router-view组件进行匹配组件的渲染,并与Header组件进行整合,来形成我们app的主题页面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//App.vue
<template>
<div id="app">
<navigation></navigation>
//视图将显示在router-view的位置
<router-view></router-view>
</div>
</template>
<script>
import Navigation from './components/Header'
export default {
name: 'app',
components: {
Navigation
}
}
</script>

c.配置路由
创建router.js,进行路由规则的设置,来定义各路径跳转到的组件。同时引用vue-router插件,将router实例对象暴露出去。当然,我们需要提前写好Foo,Bar组件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
//引用组件
import Foo from './components/Foo'
import Bar from './components/Bar'
// 定义路由
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]
const router = new VueRouter({
routes
})
export default router;

d.整合app
最后,我们将配置好的路由对象与我们的app进行整合,在入口文件中通过router参数进行配置:

1
2
3
4
5
6
7
8
9
10
import Vue from 'vue'
import App from './App'
import router from './router'
new Vue({
el: '#app',
template: '<App/>',
router: router,
components: { App }
})

到此,我们基本的带有路由导航的内容已经基本实现,很简单。通过点击foo,bar两个不同导航,我们可以进行跳转。

路由效果

1.2 嵌套路由实现二级导航

实现二级导航和一级导航的思路一样,只不过在路由配置中稍有不同,首先,我们定义一个导航组件。

1
2
3
4
5
6
7
8
9
10
11
12
13
<template>
<div id="nav-left">
//通过遍历生成router-link
<router-link v-for="item in items" :to="item.to" class="nav-link">{{item.title}}</router-link >
</div>
</template>
<script>
export default {
name: 'nav-left',
props: ['items'],
};
</script>

接着,我们改写之前的foo组件,让其包含一个左侧菜单,来跳转不同的右侧内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<template>
<div id="main-content">
<nav-left :items="items"></nav-left>
<router-view></router-view>
</div>
</template>
<script>
import NavLeft from './NavLeft'
export default {
name: 'bar',
data () {
return {
items: [
{ to: '/foo/111/111', title: '111' },
{ to: '/foo/222/222', title: '222' },
]
};
},
components: {
NavLeft
}
};
</script>

最后配置路由,使用children字段配置子路由即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
path: '/foo',
component: Foo,
children: [
{
path: '111/:id',
component: A
},
{
path: '222/:id',
component: B
},
]
}

至此,我们可以通过点击header导航,来进行一级路由的切换,通过左侧导航,来实现二级路由的切换了。

1.3 实现路由重定向

我们会发现,第一次进入页面的时候,未点击导航,下侧内容并不会现实出来,显然这不是我们想要的效果,我们想让第一个一级导航和第一个二级导航作为我们默认选中的内容。因此我们使用重定向来完成它:

使用重定向的方法非常简单,直接通过routes配置来完成:

1
2
3
routes: [
{ path: '/a', redirect: '/b' }
]

因此我们在原有配置基础上进行以下修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//首页重定向到第一导航
{ path: '/', redirect: '/foo'},
{
path: '/foo',
component: Foo,
children: [
{
path: '111/:id',
component: A
},
{
path: '222/:id',
component: B
},
],
//重定向到第一个子组件
redirect: '/foo/111/111'
},

进入首页,即可自动展示内容。

2.控制路由跳转规则

我们往往会有这样的需求,因为用户未进行某种操作而禁止用户进行跳转,因此我们会需要拦截导航,在跳转是进行判断,完成或取消跳转。因此我们使用钩子函数来进行。

钩子分为以下几种:

1.全局钩子

当一个导航触发时,全局的 before 钩子按照创建顺序调用。钩子是异步解析执行,此时导航在所有钩子 resolve 完之前一直处于 等待中。

1
2
3
4
5
6
7
8
9
10
router.beforeEach((to, from, next) => {
// to: 目标路由对象
// from: 当前路由对象
// next: resolve function
// 三种参数: 1. 空,表示正常跳转, 2. false:中断跳转 3.'/': 跳转新导航
})
router.afterEach(route => {
// 没有next方法 不能改变导航
})

2.特定路由钩子
直接在routes进行配置,和全局钩子是一样的,此钩子只针对本路由有效。

3.组件内钩子

1
2
3
4
5
6
7
8
9
10
11
12
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) => {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当钩子执行前,组件实例还没被创建
},
beforeRouteLeave (to, from, next) => {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}

3.实现懒加载

显然,当系统越来越大时,在进入页面的时候将所有资源都一起进行加载显然是不合理的,我们更希望在需要访问某组件时再去请求它的相关资源。可以配合webpack进行配置:

将组件定义成异步组件:

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

我们会发现,在进行打包时,webpack会自动将文件进行拆分:

路由效果

当请求新的路由时,才会对相应资源进行请求:

路由效果

同时,我们可以将组件进行分组打包到同一个异步的chunk中

1
2
3
const Foo = r => require.ensure([], () => r(require('./Foo.vue')), 'group-foo')
const Bar = r => require.ensure([], () => r(require('./Bar.vue')), 'group-foo')
const Baz = r => require.ensure([], () => r(require('./Baz.vue')), 'group-foo')

通过分组方式,会发现A,B两个组件被打包成一个文件,很好很强大
路由效果

项目源码