imyanglan / Vue-xuexi

0 stars 0 forks source link

Vue学习笔记 day7 #13

Open imyanglan opened 4 years ago

imyanglan commented 4 years ago

Vue Router详解

学习地址:(https://www.bilibili.com/video/av89760569?p=99)

Vue Router

说起路由你想起了什么?

路由是一个网络工程里面的术语 路由(routing)就是通过互联的网络吧信息从源地址传输到目的地址的活动,路由的作用就是把某个东西从它的源地址通过某种转发给他最终转发到目的地址。比如说你想给你某个地方的朋友发一条消息,它不仅要经过你家里的路由器,其实在整个网络里面传输的话它要经过很多个路由转发。

网络工程,一方面学编程,另一方面就是学习配置各种路由器、交换机。

在生活中,我们有没有听说过路由的概念呢?比如路由器

路由器提供了两种机制:路由和转送
路由器中有一个非常重要的概念叫路由表

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

我们的电脑在连上我们的路由器的时候,路由器都会给我们分配一个IP地址(如:192.168.110)这种IP地址叫内网IP,如果我们在家里通过路由器配置这样一个IP地址,在公司也能通过路由器配一个这样的IP地址。但是在互联网中IP地址都是唯一的,因为在互联网当中都是通过唯一的IP地址找到对应的电脑。之所以以上条件没有冲突就是因为内网IP,内网IP只有在你当前的网络中这个IP地址才是有效的,所以在别的地方你依旧可以用相同的IP地址,但是在内网中你想再设一个相同的IP地址它就会冲突了。而对外连接的“猫”就有个公网IP地址,公网IP地址才不会重复,也就是通过公网的IP找到你的“猫”,再通过“猫”传给连接的路由器,而路由器将受到的信息再进行一次转发,它根据路由器里的路由表,把我们的内网IP和电脑的mac地址一一对应起来,它就通过查询路由表里的mac地址,找到对应的内网IP再传过来。

什么是前端渲染?什么是后端渲染?`

这就要从网页的发展历史说起

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

第一个阶段:用的比较多的都是后端渲染

后端渲染:以前网页开发都是通过类似于jsp/php来开发的(以前没有js),jsp=java server page,意思用java写出来一个网页,然后把它传到浏览器这边让浏览器直接展示这个网页。

一个网站,那么多页面,服务器会如何处理?

每一个页面有自己对应的网址,也就是URL。

URL会发送到服务器,服务器会通过正则对该URL进行匹配,并且最后交给一个Controller进行处理,Controller进行各种处理,最终生成HTML或者数据,返回给前端。这就完成了一个IO操作

譬如我们打开浏览器,进入某个网址,我们浏览器会将该url请求提交到服务器,当服务器拿到我们的地址之后。首先第一步先进行一个解析,解析看一下你请求什么网页,然后它就会来到后台这边通过请求jsp这种技术,来帮你把网页写好。这个网页里包含很多东西,包含html+css+java代码,而java代码的作用是从数据库中读取数据,并且将它动态渲染到页面中,我们最终的这个页面在服务器中就已经构成了。(以前的网页是没有ajax请求的,所以网页数据都不是通过ajax传递的)服务器最终就将这个已经建立好的网页传递给我们的浏览器,而传递过来的网页就只有html+css。

这就是后端渲染,整个网页渲染出来并不是在我们前端这边渲染出来的而是在后端通过一些特殊的技术类似于jsp/php,通过这些技术把网页渲染好,然后给到前端就已经是在服务器渲染好的网页了。这叫服务端渲染,也叫后端渲染。

而如果传递多个url,根据以上的方法,在服务器这边就形成了一个映射关系了,每个url就映射一个页面,而服务器在存储、处理这种映射关系,这种路由关系这就是后端路由。

上面的操作就是后端路由,当我们页面中需要请求不同的路径内容时,交给服务器来进行处理,服务器渲染好整个页面,并且将页面返回给客户端。这种情况下渲染好的页面,不需要单独加载任何的js和css,可以直接交给浏览器展示,这样也有利于SEO的优化。

后端路由:后端处理URL和页面之间的映射关系。

后端路由的缺点:

a.一种情况是整个页面的模块都是由后端人员来编写和维护的

b.另一种情况是前端开发人员如果要开发页面,需要通过PHP和Java等语言来编写页面代码

c.而且通常情况下HTML代码和数据以及对应的逻辑会混在一起,编写和维护都是非常糟糕的事情

第二个阶段:前后端分离阶段

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

后端只负责提供数据,不负责任何阶段的内容。

这就表示我们后端这里就只是一个服务器,服务器连接着数据库就提供这些东西。这里就分为三个角色,浏览器、静态资源服务器、提供API的服务器(连接数据库的,一般大部分公司会将这两个服务器合并到一起),一旦我们在页面输入了一个地址,它必然要去服务器拿一些东西,它就要去到静态资源服务器里拿。(因为我们写的所有的代码都会放在静态资源服务器里)它会拿到三个东西就是HTML+CSS+JS

html和css这些代码浏览器可以直接渲染,但是js代码必须由浏览器执行。我们一般在网站中输入一个地址通常是先通过该url访问它的静态资源服务器,将一些静态资源先访问下来进行对网页的渲染。当浏览器再去执行js代码的时候,一般js代码里面才有对应的API请求,然后当浏览器在执行的过程中一旦发现有API请求,它肯定就会想提供API接口的服务器发送请求,去请求API相关的资源,服务器则再将请求到的数据返回给浏览器。然后通过其他的js代码,针对这些请求过来的数据创建div标签这些元素,将请求过来的数据插入到这些标签里面,最终浏览器将这部分js代码的部分渲染到网页上面。这就是前端渲染(就是浏览器自己解读代码自己给自己进行渲染)

后端只提供API来返回数据,前端通过Ajax获取数据,并且可以通过JavaScript将数据渲染到页面中。这样做最大的优点就是前后端责任的清晰,后端专注于数据上,前端专注于交互和可视化上。 并且当移动端(IOS/Android)出现后,后端不需要进行任何处理,依旧使用之前的一套API即可。

前端渲染:浏览器中显示的网页中的大部分内容,都是由前端写的js代码在浏览器中执行,最终渲染出来的,这个过程叫做前端渲染。

第三个阶段:单页面富应用(前端路由阶段)

其实SPA最主要的特点就是在前后端分离的基础上加了一层前端路由,也就是由前端来维护的一套路由规则。

SPA:simple page web application(单页面富应用) 整个网页就只有一个HTML页面

以前开发的网站一般都有很多的html和css等页面,多个url对应多个页面。而这个只有一个页面就是index.html,甚至可能也只有一个css和js。它把所有的东西都放在这一个html+css+js中,也就是说我们开发的整个网站就只有这三样东西。而当我们从静态资源服务器中请求下来的html+css+js,就是整个网站全部的资源。

虽然我们点开网页时将全部的资源都下载下来了,但不会全部执行。而是当你点击某个网页时,将该页面需要的资源抽取出来,然后在这个网站中渲染出来,而点另一个网页时,则将另一个页面需要的资源抽取出来,再次渲染。当我们把所有资源都下载下来的话,必须得有一个技术作为支撑,来区分这些页面。就是我们的前端路由。

前端路由怎样来提供技术支撑呢?

配置一些映射关系,比如:我们在点击某一按钮的时候,浏览器上面它会生成一个url。而生成的这个url不会向服务器请求其他资源,它只会通过一些js代码的判断,从下载下来的全部资源中抽取出来要显示该按钮相关的东西,然后放在这个页面上进行显示,当点击另一个按钮的时候,它就会再去里面取出它对应的资源进行渲染。(其实在这里面抽取的资源,在我们Vue里面的话就是一个一个的组件)

所以上面看起来是一个HTML+CSS+JS其实就是将多个html、css、js打包在一个文件里了。因为并不是一开始所有的代码都会执行的,它会在前端自动监听浏览器,一旦发现浏览器上面的url发生改变,和js里的对应的话,它就会通过从js里找到属于这部分组件相关的东西,然后在我们的界面上进行渲染。所有的页面都是从全部资源里分离出来的各个组件组成,而通过前端路由来映射我们浏览器上面的哪一个url来渲染我们全部资源中哪一些组件一起组成的一个页面。(一个url对应一个页面)

前端路由:前端管理的一个映射关系,一个url对应一个大组件也就是一个页面,而它们之间的这种映射关系是由前端来维护的所以叫做前端路由。

前端路由的核心是什么呢?

改变url时,页面不进行整体刷新。因为把整个页面刷新意味着要去服务器请求整个一个新的一套资源,让我们前端自己监听url的改变就可以了,当url发生改变的时候不向服务器请求任何的资源。(而一进行刷新肯定就向服务器重新发送请求了,所以不要随便刷新)

Vue Router 就是前端路由

而前端路由它有一个必须要实现的东西,就是在改变URL的时候,让页面不要进行刷新。

很多的网站,一旦在我们更改URL的时候,它会向服务器请求我们更改后的URL对应的一些资源。而现在需要做的是我们更改URL就只是更改它,并不需要它重新再向服务器再请求资源,因为我们需要内部在前端这里监听这个URL的改变。

--要实现在改变URL的时候让页面不要进行刷新有两种模式

URL的hash

href->hyper reference (超链接)

URL的hash也就是锚点(#),本质上是改变window.location的href属性。我们可以通过直接复制location.hash来改变href,但是页面不会发生刷新。

直接在页面中运行location.hase,通过这种方式去更改我们的URL,URL的地址发生了改变,但页面不会进行刷新。所以其中一种监听URL的改变就是用hash的方式,当发现用hash进行对URL的改变时,它不会再向服务器去请求一套资源,它会在前端这里的一个路由的映射去找,这个地址对应的需要渲染那些组件,然后它会将这些组件取出来并且放在整个网页上进行一个渲染。(它内部会监听这个改变, Vue Router会自动监听的)

HTML5的history模式:pushState

根据history这个对象来修改URL,也不会让页面进行刷新。

history.pushState()它有很多的参数,(date,titel,?url)它有一个对象参数date还有一个title参数,这两个都可以不传,最主要的就是传最后这个url,用这种方式更改URL也不会刷新页面。

push在数据结构中的栈结构用的很多,当准备要往一个栈里压入一个数据的话,它就叫做push,而它对应的另外一个东西叫pop。

栈结构它只有一个入口和出口,如果要往里面放东西就是入栈,叫做push,而拿出来一个东西叫出栈。

当我们往栈里面放入东西的时候,是这样的过程,第一个放在最底下,之后的东西就会压在前一个东西的上面。所以如果要拿东西出来的话都是后进先出,最后进去的最先出来。先进后出这就是栈结构的特点。

而使用这种栈结构的话是可以保留很多的历史记录

HTML5的history模式:replaceState

和上面的push用法一样,但区别就是它是无法进行后退的,这个是用来替换URL的,也就是用最新的URL替换之前的URL。不能像上面进行压栈和出栈的操作,所以并不能保存历史记录,无法像上面那个一样进行返回。

HTML5的history模式:go

history.back()等价于history.go(-1) history.forward()等价于history.go(1)

这三个接口等同于浏览器界面的前进后退

--认识vue-router

目前前端流行的三大框架,都有自己的路由实现 Angular的ngRouter React的ReactRouter Vue的vue-router

vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用。我们可以访问其官方网站对其进行学习

vue-router是基于路由和组件的 路由用于设定访问路径,将路径和组件映射起来。 在vue-router的单页面应用中,页面的路径的改变就是组件的切换。

--安装和使用vue-router

因为我们已经学习了webpack,后续开发中我们主要是通过工程化的方式进行开发的。所以在后续,我们之间使用npm来安装路由即可。

步骤一:安装vue-router

npm istall vue-router --save 安装好了之后可以在这里看见

第二步就是要在这里创建这样一个文件夹

在它里面创建一个index.js 然后在这个index.js里面配置所有的路由信息

步骤二:在模块化工程中使用它(因为是一个插件,所以可以通过Vue.use()来安装路由功能)

第一步:导入路由对象,并且调用Vue.use(VueRouter)

第二步:创建路由实例,并且传入路由映射配置

第三步:在Vue实例中挂载创建的路由实例

使用vue-router的步骤

第一步:创建路由组件

创建Home组件和About组件

在它们两之间相互跳转

第二步:配置路由映射

第三步:使用路由:通过<router-link>和<router-view>

:该标签是一个vue-router中已经内置的组件,它会被渲染成一个标签。 :该标签会根据当前的路径,动态渲染出不同的组件。 网页的其他内容,比如顶部的标题/导航,或者底部的一些版权信息等,会和处于同一等级。在路由切换时,切换的是挂载的组件,其他内容不会发生改变。
路由的默认路径

我们上面的内容还有一个不太好的实现,因为默认情况下,进入网站都是先展示首页,我们希望渲染首页的内容。但在上面的实现中,没有默认显示首页组件,而需要点击才会显示渲染。

如何让路径默认跳到首页,并且渲染首页组件呢?

只需要多配置一个映射就行了

配置解析:
我们在routes中又配置了一个映射
path配置的是根路径:可以为空也可以写个' / '
redirect是重定向,也就是我们将根路径重定向到/home的路径下,这样就可以得到我们想要的结果了。

我们前面说过改变路径的方式有两种: URL的hash HTML5的history

默认情况下,路径的改变使用的是URL的hash,如果希望使用HTML5的history模式的话,只有进入如下配置即可。

router-link补充

在前面的中,我们只是使用了一个属性: to ,用于指定跳转的路径

还有一些其他属性:

tag:tag可以指定<router-link>之后渲染成什么组件。

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

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

根据这个默认的class名称,可以在样式中进行对它的设置达到点击哪个按钮高亮显示哪个按钮

在进行高亮显示的导航菜单或者底部tabbar时,会使用到该类。 但是通常不会修改类的属性,会直接使用默认的router-link-active即可。

如果有多行数据需要统一修改默认名称时还有一种方式是在路由里面改

exact-active-class类似于active-class,只是在精准匹配下才会出现的class,后面看到嵌套路由时,我们再看一下这个属性。

最后补充

我们上面的连接都是通过router-link这个标签在使用,如果我们不想使用router-link,可能需要执行对应的JavaScript代码,这个时候这么办呢?

路由代码跳转

  • 什么是Vue Router嵌套路由

动态路由

在某些情况下,一个页面的path路径可能是不确定的,比如我们进入用户界面时,希望是如下的路径: /user/aaaa或者/user/bbb 除了有前面的/user之外,后面还跟上了用户的ID 这种path和Component的匹配关系,我们称之为动态路由(也是路由传递数据的一种方式)

譬如建立一个用户组件,在跳转页面时需要获取到用户的id且也要调用到该组件中使用。

首先,按照之前的条件先建立这个组件,然后在更改它的url,在其后面加一个拼接的值。

APP里也要传入对应的变量,不然是无法找到我们拼接的路径的。而传入的值为变量,我们还得绑定它。

之后就是如何从用户组件中获取到传入进来的值

认识路由的懒加载

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

在我们之前也有自己配置过webpack,我们自己配置的webpack最终在打包的时候,会将所有的东西(除了图片和index.html之外)打包到一个bundle.js里面。如果打包到一个里面,到时候我们整个的bundle.js会变得非常的大,那就意味着我们从服务器第一次去请求这个静态资源的时候可能就要花费过长的时间。有可能用户在请求的过程当中,浏览器会出现短暂的空白的,因为在没请求下来之前页面上什么都渲染不出来。

Vue在构建应用程序的时候,它在帮助我们配置webpack的时候就注意到一个问题,就是对我们的js文件进行分包,而且它将里面一些css文件也进行了分包。

它这里就是将css进行了抽离,在index.html中也进行过压缩,而在压缩的这里面就有被导入的css。

js也不是打包到一个文件中的

app:当前应用程序开发的所有业务代码,我们自己写的所有js代码。

manifest:为了打包的代码做底层支撑的 在之前讲的导入导出中,我们既可以用ES6的导入导出,也可以用common.js的导入导出。而我们最终打包的js里其实是不支持common.js的,甚至很多浏览器连ES6都不支持,所以它打包出来的这些js里面,要通过某种方式让她对我们之前的那种导入导出是有效的而且也是让浏览器能识别的。也就是说它底层对我们这些导入导出,它要写一些代码对它做支撑的,这里面就是打包的这种东西。

vender:供应商(第三方框架比如Vue,vue-router也属于,因为是协助开发的)这里面都是打包的需要用到的第三方的框架等不属于我们自己搭建的内容。

如果我们想看manifest这个文件的话,因为这个文件是被丑化过的我们要不想让它丑化得去关闭那个插件,重新打包一遍。

我们翻到最后可以看到一个小括号里面有一个中括号,左边写的models表示找客户里面就是用来放我们一个一个模板的,将整体的模板作为数组传入到这个函数里面。

这个函数其实是一个很关键的函数,而且也给这个函数赋了很多的参数,它会在某一个位置调用这个函数并且传入一个ID,它在调这个函数的同时也给这个函数的S赋值为0。

return __webpack_require__(__webpack_require_.s = 0)

这个函数就是在为很多模块化的代码在做底层支撑

路由当中通常会定义很多不同的页面,一般情况下都是放在APP.JS这个文件中,但页面都放在一个JS文件中,必然会造成这个文件非常大,这样如果我们一次性从服务器请求下来可能会花费一定的时间,如果要解决这类的问题就需要用到我们提到的路由懒加载。

当我们在开发一个大型项目时,随着项目越来越大,我们项目里面的代码也会远远大于为打包做底层支撑的代码和导入的框架代码(app>manifest&vender)。

因为随着项目的业务越来越多而且项目的需求也越来越多,我们会不断的往里面添加代码,最终就会造成app.js这个文件会越来越大,如果这个文件越来越大的话,到时候我们用户第一次准备展示页面的时候,它需要一次性的将文件请求过来就必然需要花费一定的时间,就可能出现界面短暂空白的情况,所以为了避免这种情况我们需要将app.js这个文件进行一个分离,在开发里面最常见的做法就是,一个路由到时候打包一个JS文件,而且这个JS文件也不会一开始跟着一起请求过来,而是调用哪个就从服务器请求哪个JS文件加载下来,这种就叫做懒加载(用到时,再加载)。

路由懒加载做了什么? 主要作用就是将路由对应的组件打包成一个个的js代码块,只有在这个路由被访问到的时候,才加载对应的组件。

路由懒加载的效果

我们之前引用的格式

引用后直接使用,打包出来的最终文件是这个样子

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

最早期的路由懒加载代码 const Home = resolve =>{require.ensure(['../components.vue'],()=>{resolve(require('../components/Home.vue'))})};

方式二:AMD写法

const About = resolve =>require(['../components/About.vue'],resolve)

方式三:在ES6中,我们可以有更加简单的写法来组织Vue异步组件和Webpack的代码分割

const Home =()=> import('../components/Home.vue')

如果我们要使用路由懒加载则如下设置

而打包出来的文件会是这个样子

为何还有分包了还有APP.JS?因为我们的APP.vue也属于我们的业务逻辑,业务逻辑的东西还得有一个地方存储起来,而我们分开的只是懒加载的东西。因为我们上面用到了三个路由懒加载,所以这边下面打包的就有多分出三个新的js文件

认识嵌套路由

嵌套路由是一个很常见的功能

在开发中可能需要在路由里面会嵌套其他的路由,比如在home页面中,我们希望通过/home/news和home/message访问一些内容,也就是在之前路径的基础上再进行一个细分。一个路径映射一个组件,访问这两个路径也会分别渲染两个组件。

实现嵌套路由有两个步骤:

第一步:创建对应的子组件,并且在路由映射中配置对应的子路由

在组件内部使用<router-view>标签,告诉子组件在什么情况下显示出来显示在哪

ps:绑定嵌套路由的默认路径也和上面绑定路由的默认路径是一样的

传递参数

在路由跳转时需要传递一些消息

Profile 档案(用户界面经常这样命名)

传递参数的方式

传递参数主要有两种类型:prams和query

  1. Params的类型
  • 配置路由格式:/router/:id

  • 传递的方式:在path后面跟上对应的值

  • 传递后形成的路径:/router/123,/router/abc(传递的页面以这种形式拿参数$touter.params.userid)

  1. query的类型
  • 配置路由格式:/router,也就是普通配置

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

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

如果是大量的数据传递,最好使用query的方式,因为它传递的是一个对象

URL:协议://host(服务器地址):port(端口号默认都是80所以可以省略不写)/path(路径)?query(查询)

如果不通过router-link的方式进行跳转,而是用javascript方式进行跳转

按钮绑定方法进行跳转

$route和$router的区别
  • $router

我们在任何的一个组件中,当你去拿到this.$router,它都是一样的

我们在文件的两个位置中打印$router看他们是不是同一个东西

其实这里的router就是下图的这个router对象

它是一个大的对象,它里面有一些方法

这些方法就放在VueRouter这个类里,所以才可以在某一个位置可以直接通过this.$router调用这些方法

  • $route

我们打印这个就是访问的当前路由(处于活跃的路由)

还可以去看源码加深了解

查看当前vuerouter的版本

我们在用任何的组件/插件的时候,必须调用Vue.use()这个方法。因为当我们在执行这个方法的时候就是让他的内部的对象/插件执行install方法(安装的方法)

从源码来看当执行VueRouter之后,它会在install里做什么事情,但我们发现一开始进来的install是空的。

但当我们走到最下面就发现,它会往install里赋新的值

这个值也就是从上面调用的进来的一个值,由路径调用可得是从这个文件夹里调用过来的

就是把这个install赋值给上面了

我们先来看这install里面的这个东西

为什么我们在代码里能使用?看下图做了什么事情

Vue.component是注册一个全局组件一旦注册了这个全局组件任何地方都可以使用

它注册的名字格式是驼峰命名法,使用时有两种写法,用驼峰命名法或者是全部小写不同单词用-号连接起来就行(如上方列举格式),只是后者更为规范。

就是因为注册了全局组件所以可以调用

所有的组件对象都继承自Vue类的原型

如果我在Vue原型上增加一个test方法(或属性),意味着不只是Vue多一个test方法(或属性),所有的组件都会多一个test方法(或属性)。

下图就是验证这个说法

我们开始读一遍install里的源码

它在执行install的时候其实有在把一个Vue类传进来而这个Vue就是下图指向的main函数里创建的Vue

这里面有一个方法,Object.defineProperty()它是Vue的响应式实现的核心这个方法是做什么的?

而this._routerRoot._router就是代码里面main.js里挂载的router,这里就是把挂载的router赋值给到$router

而上面那个router是如何挂载进去的呢?

如下图所示

所以挂载的router永远等于$router

如何读下面的route也是类似的,但是这里的route是动态的

谁处于活跃状态谁就被传递过去

  • 什么是Vue Router导航守卫

监听路由来回跳转的过程,然后在对应的监听函数里做想做的操作

为什么使用导航守卫?

我们来考虑一个需求:在一个SPA应用之后,如何改变网页的标题呢?

网页标题是通过<title>来显示的,但是SPA只有一个固定的HTML,切换不同的页面时,标题并不会改变。

但是我们可以通过JavaScript来修改<title>的内容.window.document.title='新的标题'

那么在Vue项目中,在哪里修改?什么时候修改比较合适呢?

任何的组件和Vue实例都是有生命周期的,其中有一个生命周期函数叫created,就是每次当组件创建出来之后会回调的生命周期函数。

mounted:当我们将这些<template>模板里的东西挂载到整个dom上面之后就会来回调这个生命周期函数。

updated:它是在我们界面发生更新的时候,只要是界面发生一次刷新就会来这边执行这个回调函数

我们就可以在这个生命周期函数进行对title的修改,这样跳转页面的时候,每次都会创建新的组件就会回调这个函数,就能将对应的页面的title进行更改。

但是这样实现有一个问题,一个功能的实现我们得去那么多文件去实现同一个功能,就很费劲。既然这些都是路由跳转,那能不能监听一下路由跳转的过程,然后当他进行跳转的时候将它改成对应的title?那怎么监听呢?这时就可以用到全局导航守卫了。

如果我们想要监听全局的路由跳转,只需要拿到这里的这个router对象,如下图

beforeEach本身是一个函数,当我们调这个函数的时候它又让我们传入另外一个函数

beforeEach:前置钩子(钩子(hook)也是回调的意思,这里就是在路由跳转之前进行的一个回调)

它让我们传入的是一个guard(守卫),而它要我们传一个NavigationGuard,这是什么东西呢?

在这里把这个东西定义为类型了,相当于把这个东西起了一个别名这个东西的别名就是括号里包含的内容,这就是一个箭头函数,所以beforeEach传的就是这个函数,这个函数本身又有三个参数to、from、next

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

form:当前导航即将要离开的路由对象

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

而且在这个beforeEach里必须调next,而这个next本身它又是一个函数

这个函数的目的就是为了让你调用一下next,如果不调就不会进行下一步了。

如果我们没有实现beforeEach这个方法它内部会自动调用next,因为通过我们的实现,把它内部的实现覆盖掉了,所以如果我们必须得在里面调用next,不然会出问题它不会进行下一步了也就不能进行路由跳转。

而另外两个参数的意思就从哪个路由跳到哪个路由(form跳转到to)

而这里我们就能利用to知道是跳转到哪个路由随之改变它的title!

to没有title这个属性,但它的类型是route型

而这个route就是我们定义的那些路由

如果想在这些路由里加上一些东西的话,就要在路由里加上meta(元数据)在这里面加上title属性

meta:描述数据的数据

我们在这些路由里分别写好对应的title,然后从to里获取到这个属性,就能得到对应路由的title属性的

这时我们会遇到一个问题,就是首页的title会变成undefined,点击其他的都不会有问题

为什么第一个会变成undefined呢?

因为第一个有路由的嵌套,如果你是这个路径它就会正常显示title为首页

但现在不是这个路径,而是多了一个news路径,所以现在所拿到的to有点问题

我们会发现meta里没有title,这个title到哪去了呢?我们打开matched从里面找

发现在matched的第一条数据中的meta里有title,所以我们的代码只需要这样改就行

这样就是通过路由导航完成了上面的需求了
导航守卫补充
  • [ ] 补充一:如果是后置钩子,也就是afterEach,不需要主动调用next()函数,后置钩子是在路由跳转之后调用。

  • [ ] 补充二:上面我们使用的导航守卫,被称之为全局守卫,除了上面两种守卫还有下面这两种守卫。

路由独享的守卫:只有我们进入到某个路由里面才会进行回调的一个函数

组件内的守卫

keep-alive是Vue内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。

keep-alive:切换时不会创建新的组件,而是将之前组件的状态保留下来。

它们有两个非常重要的属性:
include:(包含)字符串或正则表达式,只有匹配的组件会被缓存
exclude:(排除)字符串或正则表达式,任何匹配的组件都不会被缓存

router-view也是一个组件,如果直接被包在keep-alive里面,所以路径匹配到的试图组件都会被缓存。

当组件没被包在keep-alive里保持状态,会被频繁的创建!

我们先创建两个生命周期函数,一个是组件创建时被调用,一个是组件销毁时被调用

我们看打印结果就知道我们在反复跳转的过程之中,组件也是被反复创建又销毁。我们每次点击进来时都会创建一个新的组件,就因为是新创建的所以每次进来都会默认显示新闻。

而如果我们现在不希望它每次都创建一个新的组件,希望能保持之前的状态,这时候我们就能使用这个组件keep-alive

我们把之前的组件放到keep-alive里,在运行一遍程序可以看到没有打印销毁了,而再回去也不会重新创建,这个时候就只会创建一次。可以大大的提高性能,有时候需要重新创建,但大部分情况可能就类似于现在这种情况,一般都不需要创建一个新的。

但是这里还有一点问题,就是我们点击到其他路由再回来的时候,我们之前选择了消息但后面回来展示的是新闻而不是消息。造成这个原因是因为当我们跳转跳回首页的时候,相当于给路由传了个home,而一旦你给它传home的时候因为这个news是个缺省值,它会自动从home跳到news这里。

这种情况有种解决方案就是不要在router里配置缺省值了

但是会有另外一个问题,就是会回到之前的第一次进来默认不会默认展示新闻的内容。要解决这个问题,可以用一个新的函数activated(活跃的),这个函数也是一个会被回调的函数,如果页面有keep-alive缓存功能,这个函数会触发。它还有对应的另外一个函数deactivated(不活跃的)。

所以我们可以在activated函数里给路由赋值,这样就实现了第一次进来默认展示新闻的内容

但这样还有个问题,因为是写死的所以我们点击了消息之后跳转别的页面再回来,还是会默认给这个固定值,这就和之前重新加载组件一样了,无法实现跳转回来还是之前的操作,所以这个方法还是行不通。

这时我们可以用我们之前学的[路由守卫](导航守卫 | Vue Router (vuejs.org))

这里面有个beforeRouteLeave,我们就用它来获取离开组件后的路由地址,保存到path中,之后调用回来时就会获取到之前离开时的路由地址,就能实现我们想要的效果了。

使用了keep-alive所有页面都不会被频繁创建和销毁,因为那些页面的组件都是会被放在router-view里,因为它被keep-alive包着所以页面都是会被缓存的,所以不会频繁的创建和销毁。如果出现某种情况,需要排除掉某一个不被缓存需要怎么做?就用上面提到的属性

每个组件我们给它个name用来做标识,当需要排除时,将name名写入exclude属性就会根据这个判断那个是不需要缓存的,这样它就可以单独实现创建和销毁而其他的都要缓存,如果有两个以上想排除直接在后面加个逗号隔开就行。注意别在属性里加空格!