简介

官方介绍

Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。包含的功能有:

  • 嵌套的路由/视图表
  • 模块化的、基于组件的路由配置
  • 路由参数、查询、通配符
  • 基于 Vue.js 过渡系统的视图过渡效果
  • 细粒度的导航控制
  • 带有自动激活的 CSS class 的链接
  • HTML5 历史模式或 hash 模式,在 IE9 中自动降级
  • 自定义的滚动条行为

路由器

谈到路由,大多数人首先会想到还是路由器,上一下百度一下对于路由器的介绍

路由器是连接两个或多个网络的硬件设备,在网络间起网关的作用,是读取每一个数据包中的地址然后决定如何传送的专用智能性的网络设备。它能够理解不同的协议,例如某个局域网使用的以太网协议,因特网使用的TCP/IP协议。这样,路由器可以分析各种不同类型网络传来的数据包的目的地址,把非TCP/IP网络的地址转换成TCP/IP地址,或者反之;再根据选定的路由算法把各数据包按最佳路线传送到指定位置。所以路由器可以把非TCP/ IP网络连接到因特网上。

简单来说:路由routing)就是通过互联的网络把信息从源地址传输到目的地址的活动(来自维基百科)

可能没听懂,没事

你只需要通过一张图来理解一下他的作用

![image-20200928102611806](六、Vue Router入门/image-20200928102611806.png)

最后来解释下这张图并总结一下

  1. 路由器提供了两种机制: 路由和转送.

    • 路由是决定数据包从来源目的地的路径.
    • 转送将输入端的数据转移到合适的输出端.
  2. 路由中有一个非常重要的概念叫路由表.

    • 路由表本质上就是一个映射表, 决定了数据包的指向

后端路由阶段

早期的网站开发整个HTML页面是由服务器来渲染的。服务器直接生产渲染好对应的HTML页面, 返回给客户端进行展示.

服务器直接生产渲染好对应的HTML页面, 返回给客户端进行展示.

每个页面都有自己对应的一个url地址,用户输入一个url地址,然后这个url会传给服务器,服务器通过对url进行解析匹配,交给一个Controller处理,然后它就会去找对应的资源(html、css、js),然后服务器再在这上面通过对数据库数据的拿取后进行数据渲染,然后再将整个页面发送给前端

这样的好处是不需要单独加载js和css,直接给浏览器渲染,有利于SEO的优化

但也有缺点,你会发现,整个过程前端几乎不需要做什么事情,可能就是将静态页面写出来。然后放在一个静态资源服务器上(下面有图介绍),然后,后端人员就悲剧了,他们要去读html页面,然后去数据库拿数据,再然后将数据填充到html页面上,不仅增加了后端人员的负担,同时也使html和对应的数据处理逻辑混在一起,难以编写和维护

![image-20200928105140370](六、Vue Router入门/image-20200928105140370.png)

前端路由阶段

随着Ajax的出现,有了前后端分离的开发模式

后端只需要提供API来返回给前端数据,然后前端通过Ajax来获取数据,然后通过相应的js代码将数据渲染到页面中

这样做有一个明显的优点,后端压力小了,他只负责从数据库调取数据,处理数据和业务逻辑,而前端就可以注重交互和可视化UI上,最后将后端传过来的数据进行页面填充

随着这个过程的发展,就出现了单页面富应用阶段(SPA)

它的本质就是,在前后端分离的基础上,出现前端路由,它主要有以下特点

  • url刷新后,页面不进行整体上的刷新
  • 整个网站可能只有一个页面

它通过映射的方式,将整个html、css、js文件抽离开来,像之前学习的那样,抽离出一个个VUE组件,再通过不同的url去映射不同的vue组件

![](六、Vue Router入门/image-20200928105707350.png)

那么怎么实现多次url改变,只在一个页面上刷新呢,有两种方式,一个是通过url的hash,另一个是html5的history

先说说url的hash

  • URL的hash也就是锚点(#), 本质上是改变indow.location的href属性.
  • 我们可以通过直接赋值location.hash来改变href, 但是页面不发生刷新
  • location.hash = ‘url地址’

history接口是HTML5新增的, 它有五种模式改变URL而不刷新页面,下面其常用的方法

  1. history.pushState({data},’title’,’url’)

    将url推入(注意:这里采用类似栈的形式压入url)

  2. history.back()

    返回上一级url,类似出栈(可以联想下app还有小程序的操作模式)

    等同于history.go(-1)

  3. history.replaceState({data},’title’,’url’)

    重新指定url,这里要注意,它不能返回到上一级url,这是他和pushState的区别

  4. history.go(n)

    弹出(-n)和压入(n)的url个数

    也就是需要跳转多少级url

  5. history.forward()

    等同于history.go(1)

安装和配置

在CLI安装的时候将router这个选项选上,就会安装上了

如果没安装上,但是在后来的项目中需要用到,那么直接通过npm安装即可

1
npm install vue-router --save

然后,如果你是通过脚手架安装的话,在项目文件夹下的src里面默认会创建一个router文件夹,里面有一个index.js文件,他是关于路由相关配置

使用步骤

  1. 配置路由
    1. 导入路由对象
    2. 创建路由实例,传入路由映射配置
    3. 在Vue实例中挂载创建的路由实例
  2. 创建路由组件
  3. 配置组件和路径的映射关系
  4. 使用路由

对每一步进行详细说明

第一步:导入路由对象,并且在vue中安装路由功能

  1. 导入Vue和VueRouter
  2. 在vue中安装路由(Vue.use(VueRouter)
  3. 定义路由映射表(const routes = []
  4. 实例化路由对象并将映射表挂载上去(const router = new VueRouter()
  5. 导出路由对象(export default router
  6. 在main.js,Vue实例中挂载创建的路由实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//导入Vue和VueRouter
import Vue from 'vue'
import VueRouter from 'vue-router'

//在vue中安装路由
Vue.use(VueRouter)

//定义路由映射表
const routes = [] //路由映射的地方

//实例化路由对象并将映射表挂载上去
const router = new VueRouter({
routes, //将路由映射表挂载在路由实例上
mode: 'history',//将hash改为history,防止因为hash的原因url有#出现
linkActiveClass: 'active', //将路由默认的触发class改为自定义类名
})

//导出路由对象
export default router

main.js文件

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

new Vue({
router, //挂载路由对象
render: h => h(App)
}).$mount('#app')

第二步和第三步:创建路由实例,这一步思路较为简单,就是在src下的views文件夹里创建vue文件,定义自己的模板,然后再index.js里面的路由映射表里填入该vue文件的映射路由

![image-20200928145318277](六、Vue Router入门/image-20200928145318277.png)

index.js代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const routes = [

//路由默认设置
{
path:'',
redirect:'/home',
component: Home
},
{
path: '/home',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About', // route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
//这个方法样式渲染不出来
// component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
component: About
}
]

第四步:就是在App.vue主节点下,通过标签去使用路由了

注意:

  • 标签是一个vue-router中已经内置的组件, 它会被渲染成一个标签.

  • 标签会根据当前的路径, 动态渲染出不同的组件.

  • 网页的其他内容, 比如顶部的标题/导航, 或者底部的一些版权信息等会和处于同一个等级.

  • 在路由切换时, 切换的是挂载的组件, 其他内容不会发生改变.

1
2
3
4
5
6
7
8
9
<template>
<div>
<h1>我是首页</h1>
<!-- 方法一:通过router绑定的空间实现路由跳转 -->
<router-link to="/home">首页</router-link>
<router-link to="/about">关于</router-link>
<router-view class="vvv"></router-view>
</div>
</template>

效果如下

![image-20200928152010528](六、Vue Router入门/image-20200928152010528.png)

路由的默认路径

如果希望进入首页的时候默认直接显示首页路由,而不是点击首页才会出现,你可以在router下的index.js文件做这样的配置

1
2
3
4
5
6
7
8
const routes = [
//路由默认设置
{
path:'',
redirect:'/home',
component: Home
},
]

HTML5的history模式

如果你希望路径中不出现#,那么你可以在创建router实例中,通过mode将路径从hash改成history

1
2
3
4
const router = new VueRouter({
routes,
mode: 'history',//将hash改为history,防止url有#出现
})

router-link其它属性

tag: tag可以指定之后渲染成什么标签格式的组件

replace: replace不会留下history记录, 所以指定replace的情况下, 后退键返回不能返回到上一个页面中

active-class: 当对应的路由匹配成功时, 会自动给当前元素设置一个router-link-active的class, 设置active-class可以修改默认的名称.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template>
<div>
<h1>我是首页</h1>
<!-- 方法一:通过router绑定的空间实现路由跳转 -->
<!-- <router-link to="/home">首页</router-link>
<router-link to="/about">关于</router-link> -->
<router-view class="vvv"></router-view>

<!-- 取消返回 以及自定义标签-->
<router-link to="/home" replace tag="button">首页</router-link>
<router-link to="/about" replace tag="button">关于</router-link>

</div>
</template>

通过linkActiveClass可以更改全局点击是触发的class名

1
2
3
4
5
const router = new VueRouter({
routes,
mode: 'history',//将hash改为history,防止url有#出现
linkActiveClass: 'active', //将路由默认的触发class改为自定义类名
})

代码实现路由跳转

核心就是通过$router.push('url')$router.replace('url')来实现路由跳转

通过@click绑定点击事件从而代码上实现路由跳转

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
26
27
28
<template>
<div>
<h1>我是首页</h1>
<!-- 方法一:通过router绑定的空间实现路由跳转 -->
<!-- <router-link to="/home">首页</router-link>
<router-link to="/about">关于</router-link> -->
<router-view class="vvv"></router-view>
<!-- 方法二:通过代码实现 -->
<button @click="homeClick">首页</button>
<button @click="aboutClick">关于</button>
</div>
</template>

<script>
export default {
name: 'App',
methods: {
homeClick() {
// this.$router.push('/home')
this.$router.replace('/home') //禁止返回上一个页面
},
aboutClick() {
// this.$router.push('/about')
this.$router.replace('/about') //禁止返回上一个页面
}
}
}
</script>

动态路由(params)

有时候,我们可能需要根据每个用户的id或者其它唯一标识符去跳转到该用户的详细信息页面,如a用户/user/a,b用户user/b,这个时候我们就需要用到动态路由去实现这一功能,如下代码所示

router: index.js

1
2
3
4
5
{
path: '/user/:userid',
name: 'User',
component: User,
}

App.vue

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>
<h1>我是首页</h1>
<router-link :to="'/user/'+ userid" tag="button">用户</router-link>
</div>
</template>

<script>
export default {
name: 'App',
data() {
return {
userid: '123'
}
},
methods: {
userClick() {
this.$router.push('/user/'+this.userid)
}
}
}
</script>

<style>
</style>

User.vue(获取该id)

1
<h1>lalala,我叫{{$route.params.userid}}</h1>

路由懒加载

官方简介:

当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。

结合 Vue 的异步组件和 Webpack 的代码分割功能,轻松实现路由组件的懒加载。

官方的意思是什么呢,当我们打包一个项目时,它会将整个项目打包成一个js文件,所以当我们加载一个页面时,她都会去加载整个js文件,这样会带给服务器一定的压力,也可能会造成请求下来的过程中,界面发生短暂空白,所以将每一个页面对应的文件分开,如果需要加载该页面时,再去加载它,这样就可以避免上面的情况发生了

在之前,router加载vue文件时,是通过这个方式

1
2
3
import Home from '../views/Home.vue'
import About from '../views/About.vue'
import User from '../views/User.vue'

通过路由懒加载后,就变成这样子

1
2
3
const Home = () => import('../views/Home.vue')
const About = () => import('../views/About.vue')
const User = () => import('../views/User.vue')

打包后你就发现,js文件被分成了多个

当然,懒加载有多个方式,主要有三种

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

路由嵌套

官方介绍:

实际生活中的应用界面,通常由多层嵌套的组件组合而成。同样地,URL 中各段动态路径也按某种结构对应嵌套的各层组件,例如:

1
2
3
4
5
6
7
8
/user/foo/profile                     /user/foo/posts
+------------------+ +-----------------+
| User | | User |
| +--------------+ | | +-------------+ |
| | Profile | | +------------> | | Posts | |
| | | | | | | |
| +--------------+ | | +-------------+ |
+------------------+ +-----------------+

借助 vue-router,使用嵌套路由配置,就可以很简单地表达这种关系。

比如,我们需要访问home界面,某一个板块,例如首页的新闻界面/home/news,又或者是消息页面/home/message。我们就可以使用路由嵌套,步骤如下

  1. 创建对应的子组件, 并且在路由映射中配置对应的子路由.
  2. 在组件内部使用标签.

![image-20201001173532463](六、Vue Router入门/image-20201001173532463.png)

router index.js代码(挂载子组件路由)

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
26
27
const routes = [
{
path: '/home',
name: 'Home',
component: Home,
meta: {
title:'首页'
},
children: [
{
path: 'news',
name: 'HomeNews', //注意,嵌套路由不能加'/'
component: HomeNews,
meta: {
title:'新闻'
}
},
{
path:'message',
name: 'HomeMessage',
component: HomeMessage,
meta: {
title:'消息'
}
}]
}
]

结果

![image-20201001173920512](六、Vue Router入门/image-20201001173920512.png)

路由默认路径

![image-20201002084949584](六、Vue Router入门/image-20201002084949584.png)

参数传递

参数传递主要有两种,一种是通过params,另外一种就是通过query

  1. params的类型:

    • 配置路由格式: /router/:id
    • 传递的方式: 在path后面跟上对应的值
    • 传递后形成的路径: /router/a, /router/b
  2. query的类型:

    • 配置路由格式: /router, 也就是普通配置

    • 传递的方式: 对象中使用query的key作为传递方式

    • 传递后形成的路径: /router?id=123, /router?id=abc

使用方式

使用方式主要有两种,一种是通过标签的形式,另外一种是直接通过js代码实现

params传递参数的方式在动态路由那里已经有讲到,这里主要讲query传递参数的方式

router-link标签方式(path指定路径,query指定传递的参数)

1
<router-link :to="{path:'/home/message',query:{name:'你好啊',age:19}}" tag="button">消息</router-link>

js方式

自定义标签

1
<button @click="homeMessageClick">消息</button>

点击绑定事件

1
2
3
4
5
6
7
8
homeMessageClick() {
this.$router.push({
path: '/home/message',
query: {
name: '小米',
age: 18
}})
}

URL

简介:

URL指的是统一资源定位符(*Uniform Resource Locator*)。URL无非就是一个给定的独特资源在Web上的地址。理论上说,每个有效的URL都指向一个独特的资源。这个资源可以是一个HTML页面,一个CSS文档,一幅图像,等等。而在实际中,有一些例外,最常见的情况就是URL指向了不存在的或是被移动过的资源。由于通过URL呈现的资源和URL本身由Web服务器处理,因此web服务器的拥有者需要认真地维护资源以及与它关联的URL。

以下源于百度百科

protocol :// hostname[:port] / path / [;parameters][?query]#fragment

protocol(协议)

指定使用的传输协议,下表列出 protocol 属性的有效方案名称。 最常用的是HTTP协议,它也是WWW中应用最广的协议。

file 资源是本地计算机上的文件。格式file:///,注意后边应是三个斜杠。

ftp 通过 FTP访问资源。格式 FTP://

gopher 通过 Gopher 协议访问该资源。

http 通过 HTTP 访问该资源。 格式 HTTP://

https 通过安全的 HTTPS 访问该资源。 格式 HTTPS://

mailto 资源为电子邮件地址,通过 SMTP 访问。 格式 mailto:

MMS 通过 支持MMS(流媒体)协议的播放该资源。(代表软件:Windows Media Player)格式 MMS://

ed2k 通过 支持ed2k(专用下载链接)协议的P2P软件访问该资源。(代表软件:电驴) 格式 ed2k://

Flashget 通过 支持Flashget:(专用下载链接)协议的P2P软件访问该资源。(代表软件:快车) 格式 Flashget://

thunder 通过 支持thunder(专用下载链接)协议的P2P软件访问该资源。(代表软件:迅雷) 格式 thunder://

news 通过 NNTP 访问该资源。

hostname(主机名)

是指存放资源的服务器的域名系统(DNS) 主机名或 IP 地址。有时,在主机名前也可以包含连接到服务器所需的用户名和密码(格式:username:password@hostname)。

port(端口号)

整数,可选,省略时使用方案的默认端口,各种传输协议都有默认的端口号,如http的默认端口为80。如果输入时省略,则使用默认端口号。有时候出于安全或其他考虑,可以在服务器上对端口进行重定义,即采用非标准端口号,此时,URL中就不能省略端口号这一项。

path(路径)

由零或多个“/”符号隔开的字符串,一般用来表示主机上的一个目录或文件地址。

parameters(参数)

这是用于指定特殊参数的可选项。

query(查询)

可选,用于给动态网页(如使用CGI、ISAPI、PHP/JSP/ASP/ASP.NET等技术制作的网页)传递参数,可有多个参数,用“&”符号隔开,每个参数的名和值用“=”符号隔开。

fragment(信息片断)

字符串,用于指定网络资源中的片断。例如一个网页中有多个名词解释,可使用fragment直接定位到某一名词解释。

参数获取

params的通过$route.params获取数据

query的通过$route.query获取数据

这里注意:这里是使用$route(不是$router!!!)

1
2
<h1>lalala,我叫{{$route.params}}</h1>
<h1>lalala,我叫{{$route.query}}</h1>

$route主要是用来动态获取当前路由

$router是用来获取路由对象

$route和$router的区别

$router为VueRouter实例,想要导航到不同URL,则使用$router.push方法

$route为当前router跳转对象(动态获取到当前跳转到的路由路径),里面可以获取当前路径的name、path、query、params等

所有组件都会继承自Vue的原型(prototype)

如果你给Vue实例定义一个属性

1
Vue.prototype.name = '你好'

那么,它的组件同样也会继承这个name属性,你可以在子组件中去访问这个属性

vue中使用Object.defineProperty(‘类’,’键’,’值’)去定义类的属性

导航守卫

简介以及使用

首先解释下导航的含义:“导航”表示路由正在发生改变。

然后上官方介绍

正如其名,vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。有多种机会植入路由导航过程中:全局的, 单个路由独享的, 或者组件级的。

记住参数或查询的改变并不会触发进入/离开的导航守卫。你可以通过观察 $route 对象来应对这些变化,或使用 beforeRouteUpdate 的组件内守卫。

其他较为容易理解的解释

vue-router提供的导航守卫主要用来监听监听路由的进入和离开的.

vue-router提供了beforeEach和afterEach的钩子函数, 它们会在路由即将改变前和改变后触发.

这里提出一个相关的案例需求,如果希望自己的页面每次跳转时,网页标题都会相应的改变,变成与其匹配的title标题呢,有两种方式

  1. 通过mounted声明周期函数, 执行对应的代码进行修改

  2. 另外一种就是导航守卫,通过监听路由跳转的不同页面去动态更改(index.js)

    首先在index.js文件中为每个路由定义meta属性定义所需数据,接着在后面定义一个beforeEach钩子函数去动态定义标题

    • 导航钩子的三个参数解析:

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

      • from: 当前导航即将要离开的路由对象.

      • next: 调用该方法后, 才能进入下一个钩子

    ![image-20201002093437922](六、Vue Router入门/image-20201002093437922.png)

导航守卫类型

全局导航守卫

  1. router.beforeEach()~前置钩子
  2. router.afterEach()~后置钩子

路由独享守卫

组件导航守卫

完整的导航解析流程

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

keep-alive

keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。(使用created()和destroyed()验证该组件)

有两个组件函数必须在它的基础下才能使用

  • activated() 当前路由活跃状态下调用的函数
  • deactivated() 路由跳转后之前路由调用的函数

属性

pinclude - 字符串或正则表达,只有匹配的组件会被缓存

pexclude - 字符串或正则表达式,任何匹配的组件都不会被缓存

实现保留首页切换后最后一次保留的位置

使用keep-alive标签包裹router-view

1
2
3
<keep-alive>
<router-view/>
</keep-alive>

使用组件内导航守卫在当前路由跳转到其他路由后最后一次定位到的嵌套路由保留下来,假设现在首页有新闻,消息等子路由,然后你切换到另一个和首页同级的路由,之后再切换回首页时,想保留首页最后一次点击的子路由,你就可以使用这个标签完成这个功能

  1. 首先在当前组件内定义变量接收path路径

    1
    2
    3
    4
    5
    data() {
    return {
    path: '/home/news'
    }
    }
  2. beforeRouteLeave()接收最后一次的路由路径

    1
    2
    3
    4
    beforeRouteLeave(to,from,next) {
    this.path = this.$route.path
    next()
    }

    使用activated函数在当前组件活跃状态实现路由跳转

1
2
3
activated() {
this.$router.push(this.path)
}