路由

什么是路由?提到路由,可能第一反应是无线路由器,但这里的路由指的是页面跳转的规则,我们常见的网站,从A页面跳转到B页面是如何定义的,页面内容如何回显,这些都可以算作是web路由的一部分。路由分为前端路由和后端路由

后端路由

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

但是, 一个网站, 这么多页面服务器如何处理呢?

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

  • URL会发送到服务器, 服务器会通过正则对该URL进行匹配, 并且最后交给一个Controller进行处理.

  • Controller进行各种处理, 最终生成HTML或者数据, 返回给前端.

  • 这就完成了一个IO操作.

上面的这种操作, 就是后端路由.

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

后端路由的缺点

  • 一种情况是整个页面的模块由后端人员来编写和维护的.
  • 另一种情况是前端开发人员如果要开发页面, 需要通过PHP和Java等语言来编写页面代码.
  • 而且通常情况下HTML代码和数据以及对应的逻辑会混在一起, 编写和维护都是非常糟糕的事情.

前端路由

前后端分离阶段

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

单页面富应用阶段

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

前端路由的核心是改变URL,但是页面不进行整体的刷新。

为了构建SPA,vue引入了前端路由系统vue-router。

vue-route有两种模式:history模式和hash模式

hash模式

vue-router默认使用的是hash模式。

hash模式背后的原理是onhashchange事件

localtion是js里管理地址栏的内置对象,是window对象的一部分,可通过window.localtion访问。

由于hash发生变化的url都会被浏览器记录下来,使得浏览器的前进后退都可以使用了,尽管浏览器没有请求服务器,但是页面状态和url关联起来。后来人们称其为前端路由,成为单页应用标配。

比如http://www.abc.com/#/index,hash值为#/indexhash模式的特点在于hash出现在url中,但是不会被包括在HTTP请求中,对后端没有影响,不会重新加载页面

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

image-20200614082006857

history模式

history模式利用了HTML5 History Interface中新增的pushState()replaceState()方法。这两个方法应用于浏览器的历史记录栈,提供了对历史记录进行修改的功能。只是当他们进行修改时,虽然修改了url,但浏览器不会立即向后端发送请求。

当使用history模式时,url就像正常的url,例如http://abc.com/user/id相比hash模式更加好看。特别注意,history模式需要后台配置支持。如果后台没有正确配置,访问时会返回404。

通过history api,我们丢弃了丑陋的#,但是有一个缺点,当刷新时,如果服务器中没有相应的相应或者资源,会分分钟刷出一个404来(刷新需要请求服务器)。所以history模式不怕前进,不怕后退,就怕刷新。

history.pushState()

image-20200614083252403

pushState的存储结构相当于栈(先进后出),使用这个方法能把元素压进栈,并显示当前栈顶元素。可以前进后退。也就存在历史记录。

image-20200614083803868

history.replaceState()

image-20200614084050885

替换当前的url,但是不能保存历史记录。也就不能后退到,之前replace的url。

image-20200614084500110

其他的方法

history.go(number|URL) 方法可加载历史列表中的某个具体的页面。

该参数可以是数字,使用的是要访问的 URL 在 History 的 URL 列表中的相对位置。(-1上一个页面,1前进一个页面)。或一个字符串,字符串必须是局部或完整的URL,该函数会去匹配字符串的第一个URL。

history.go(-1)等价于history.back()浏览器后退

history.go(1)等价于history.forward()浏览器前进

Vue Router的安装和使用

image-20200614090709766

可以通过Vue CLI创建项目的时候,选择安装下载Vue Router或者通过npm下载npm install vue-router --save

image-20200614085350010

接着我们在src目录下创建一个router目录,编写index.js文件。

code-snapshot (49)

main.js中Vue实例导入router目录中的index.js。设置为router选项的属性值。(导入的是一个目录会自动导入改目录下的index.js)

code-snapshot (50)

接下来就能使用Vue Router了。我们只要配置好path和相对应的component组件就可以了。

路由映射配置和呈现

在src包中创建两个.vue文件Home,About

image-20200614162410656

image-20200614162426348

在编写index.js引入单文件组件对象

image-20200614162518282

code-snapshot (51)

在App.vue文件中呈现出来。通过router-linkrouter-view

image-20200614162806065

code-snapshot (52)

<router-link>: 该标签是一个vue-router中已经内置的组件, 它会被渲染成一个<a>标签

<router-view>: 该标签会根据当前的路径, 动态渲染出不同的组件.

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

接着运行项目查看效果npm run dev

GIF

配置路由的默认首页

前文中,我们打开项目,默认是没有任何一个组件被显示的。所以我们要配置一个默认的组件进行显示

image-20200614163504718

添加path值为'/'或者为空,通过一个新的属性redirect值为'/home'重定向到'/home'从而显示Home组件

image-20200614163732952

这样进入localhost:8080/默认重定向到localhost:8080/#/home从而显示Home组件内容

修改路由模式为history

通过运行项目可以查看到我们的url地址都会由#这是因为我们vue-router默认使用的hash模式,也就是锚点,所以会有#这是不符合我们日常见到的url格式的。所以我们要修改路由的模式为history

修改方式很简单,我们在我们的路由实例对象中,增加一个mode选项,值为'history‘即可使用history模式。

image-20200614164100034

查看页面效果

GIF1

router-link属性

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

tag: tag可以指定<router-link>之后渲染成什么组件, 比如这行的代码<router-link to='/home' tag='li'>会被渲染成一个<li>元素, 而不是<a>

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

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

image-20200614165402516

image-20200614165236601

GIF2

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

image-20200614165445093

修改成功

image-20200614165507507

不过这样一个一个修改比较麻烦,所以很少使用。若想从根本修改这个class名的话,可以通过vue-router的实例对象中的linkActiveClass设定值来进行修改

将先前设置的active-class取消,在router目录下index.js中添加代码

image-20200614165847381

image-20200614165935956

代码跳转路由

image-20200614173712778

在 Vue 实例内部,你可以通过 $router 访问路由实例。因此你可以调用 this.$router.push

image-20200614173753373

不用在前面加/否则会控制台报错,也可以使用$router.replace()则没有历史记录。

查看效果

GIF3

动态路由

在某些情况下,一个页面的path路径可能是不确定的,比如我们进入用户界面时,希望是如下的路径:

/user/aaaa或/user/bbbb

除了有前面的/user之外,后面还跟上了用户的ID。这种path和Component的匹配关系,我们称之为动态路由(也是路由传递数据的一种方式)。

编写一个User.vue组件

image-20200614190903997

添加路由映射配置修改index.js

image-20200614190956454

App.vue添加代码

image-20200614191441914

查看页面效果

image-20200614191525188

单文件组件获取传递的参数值$route.params.参数名

image-20200614191946441

image-20200614192120777

路由的懒加载

使用npm run build进行打包。不同与前文种使用webpack打包后,所有的引用文件都被打包成了一个main.js文件。使用vue-cli创建的vue项目,打包后会把不同类型文件分包打包,例如css文件在css目录,js文件在js目录下。

image-20200701203051791

其中app.xxxxx.js是当前应用程序开发的所有代码(业务代码)

mainxxxxx.js为了打包代码做底层支撑

vendorxxxxx.jsvendor(提供商,第三方vue等代码)

官方给出了解释:

  • 当打包构建应用时,Javascript 包会变得非常大,影响页面加载。

  • 如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了

官方在说什么呢?

  • 首先, 我们知道路由中通常会定义很多不同的页面.

  • 这个页面最后被打包在哪里呢? 一般情况下, 是放在一个js文件中.

  • 但是, 页面这么多放在一个js文件中, 必然会造成这个页面非常的大.

  • 如果我们一次性从服务器请求下来这个页面, 可能需要花费一定的时间, 甚至用户的电脑上还出现了短暂空白的情况.

  • 如何避免这种情况呢? 使用路由懒加载就可以了.

路由懒加载做了什么?

  • 路由懒加载的主要作用就是将路由对应的组件打包成一个个的js代码块.

  • 只有在这个路由被访问到的时候, 才加载对应的组件

image-20200701202024112

image-20200701202148784

推荐使用第三种方式实现路由懒加载效果

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

image-20200701202502137

使用懒加载后npm run build进行项目打包。可以发现js目录中多出了三个js文件,分别对应哪3个使用路由懒加载的单文件组件对象。当只有在这个路由被访问到的时候, 才加载对应的组件。

image-20200701203652093

嵌套路由

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

  • 比如在home页面中, 我们希望通过/home/news和/home/message访问一些内容.

  • 一个路径映射一个组件, 访问这两个路径也会分别渲染两个组件.

路径和组件的关系如下

image-20200701205041578

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

  • 创建对应的子组件, 并且在路由映射中配置对应的子路由.

  • 在组件内部使用<router-view>标签.

首先创建HomeMessage.vueHomeNews.vue

image-20200701205200285

image-20200701205212374

导入两个vue文件,接着配置路由index.js文件。在相对应的路由路径中配置children属性。属性值为数组,数组中可以存放多个对象用来配置路由和组件之间的应用关系。

image-20200701205900317

接着在Home.vue中配置显示路由

image-20200701210100406

npm run dev查看运行效果

GIF

嵌套路由也可以配置默认的路径, 配置方式如下,在children数组属性值中添加一个新对象,其中path属性值为'',使用redirect重定向到嵌套路由路径。

image-20200701210601657

image-20200701210810848

参数传递

准备工作

image-20200702101821527

image-20200702101853490

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

params的类型

  • 配置路由格式: /router/:id

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

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

query的类型

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

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

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

其中动态路由中使用的就是params类型传递参数

这里讲的是使用query类型传递参数

获取参数

获取参数通过$route对象获取的.

在使用了 vue-router 的应用中,路由对象会被注入每个组件中,赋值为 this.$route ,并且当路由切换时,路由对象会被更新。

在App.vue中使用v-bind绑定to属性,属性值为一个对象,path为路由路径,query为 要传入的参数,属性值为一个对象,对象中包含要传入的一个或多个属性。

image-20200702102923602

在Profile.vue中使用$route.query即可获取当前路由传递的query对象。如果相获取对象中相应的值,例如name,可以$route.query.name获取

image-20200702103124689

查看效果

image-20200702103153151

JavaScript代码

创建两个按钮,通过v-on:click绑定两个方法,userClick,profileClick

image-20200702104048664

编写对应的方法

image-20200702104154387

在vue中通过this.$router.push()中传递参数。

userClick方法中通过push方法将路由路径与vue实例中data函数中的userId一同传递。

profileClick方法中通过push方法参数为对象,对象path属性值为路由路径,query属性值为一个对象,对象中包含要传入的一个或多个属性。

查看效果

GIF

$route和$router的区别

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

$route为当前router跳转对象里面可以获取name、path、query、params等

我们在profile.vue分别将两个打印。使用vue的生命周期函数mouted

image-20200702105340223

查看打印效果

image-20200702105511026

可以发现$router为vueRouter实例。里面包含了对其属性的配置。比较明显的可以看到,其mode属性值就为我们配置的history模式。

image-20200702105712754

$route为当前router跳转对象里面可以获取name、path、query、params等

导航守卫

全局前置守卫

image-20200702111855217

image-20200702112013957

image-20200702112035617

将每个路由发生路由跳转时,html的title属性设为对应的meta.tilte属性值。必须调用next(),否则不会进行路由跳转。相当于拦截器的放行。

查看效果。发现除了首页,其他的都正常显示

image-20200702112200952

这是应为首页使用了路由嵌套。打印to可知当前对象时嵌套的路由。其中的meta值为空。

image-20200702112410494

这时候我们发现to中的matched属性值是一个数组类型,其中第一个对象就是我们要的home路由,其中meta属性值里也存在我们所写的title。所有我们要改变一下代码

image-20200702112624968

查看效果。正常

image-20200702112659836

具体信息查看官网https://router.vuejs.org/zh/guide/advanced/navigation-guards.html