文章目录
vue-router详解
认识路由
- 目前前端流行的三大框架,都有自己的路由实现:
- Angular的ngRouter
- React的ReactRouter
- Vue的vue-router
- 当然,我们的重点是vue-router
- vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用。
- 我们可以访问其官网进行学习。
- vue-router是基于路由和组件的。
- 路由用于设定访问路径,将路径和组件映射起来。
- 在vue-router的单页面应用中,页面的路径的改变就是组件的切换。
什么是路由?
-
说起路由你想起了什么?
- 路由是一个网络工程里面的术语。
- 路由routing,就是通过互联的网络把信息从源地址传输到目的地址的活动。
-
没听懂?
- 在生活中,我们有没有听过路由的概念呢?当然了,路由器嘛。
- 路由器是做什么的?你有想过么?
- 路由器提供了两种机制:路由和转送。
- 路由是决定数据包从来源到目的地的路径。
- 转送将输入端的数据传递转移到合适的输出端。
- 路由中有一个非常重要的概念叫路由表。
- 路由表本质上是一个映射表,决定了数据包的指向。
后端路由阶段
- 早期的网站开发整个HTML页面是由服务器来渲染的。
- 服务器直接生产渲染好对应的HTML页面,返回给客户端进行展示。
- 但是,一个网站,这么多页面,服务器如何处理呢?
- 一个页面有自己对应的网址,也就是URL。
- URL会发送到服务器,服务器会通过正则表达式对该URL进行匹配,并且最后交给一个Controller进行处理。
- Controller进行各种处理,最终生成HTML或者数据,返回给前端。
- 这就完成了一个IO操作。
- 上面这种操作,就是后端路由。
- 当我们页面中需要请求不同的路径内容时,交给服务器来进行处理,服务器渲染好整个页面,并且将页面返回给客户端。
- 这种情况下渲染好的页面,不需要单独加载任何的js和css,可以直接交给浏览器显示,这样也有利于SEO优化。
- 后端路由的缺点:
- 一种情况是整个页面的模块由后端人员编写和维护。
- 另一种情况是前端开发人员如果要开发页面,需要通过PHP和Java等语言来编写页面代码。
- 而且通常情况下HTML代码和数据以及对应的逻辑会混在一起,编写和维护都是非常糟糕的事情。
前后端分离阶段
- 随着Ajax的出现,有了前后端分离的开发模式。
- 后端只提供API来返回数据,前端通过Ajax获取数据,并且可以通过JavaScript将数据渲染到页面中。
- 这样做最大的优点就是前后端责任的清晰,后端专注于数据上,前端专注于交互和可视化上。
- 并且当移动端(IOS/Android)出现后,后端不需要进行任何处理,依然使用之前的一套API即可。
- 目前很多网站依然采用这种开发模式。
单页面富应(SPA页面)用阶段:
- 其实SPA最主要的特点就是在前后端分离的基础上加了一层前端路由。
- 也就是前端来维护一套路由规则。
前端路由的核心是什么呢?
- 改变URL,但是页面不进行整体的刷新。
- 如何实现呢?
url的hash和HTML5的history
- 正常情况下,我们改变URL会进行页面整体的刷新,会重新请求一些资源:
- 使用location.hash更改url不会,而会从前端路由的映射中找到响应的组件,将其渲染:
URL的hash也就是锚点(#),本质上是改变window.loaction的href属性。
我们可以通过直接赋值location.hash来改变href,但是页面不发生刷新。
- HTML5的history模式:pushState和replaceState:
- 简单来讲pushState会将历史记录压入一个栈中,调用history.back()可以返回上一个url。
- replaceState()会替换掉,无法返回。
- HTML5的history模式:go
还有一个history.forward()等价于go(1)
vue-router基本使用
-
因为我们已经学习了webpack,后续开发中,我们主要是通过工程化的方式进行开发的。
-
所以在后续,我们直接使用npm来安装路由即可。
-
步骤一:安装vue-router:
-
npm install vue-router --save
-
步骤二:在模块化工程中使用它(因为是一个插件,所以可以通过Vue.use()来安装路由功能)
- 第一步:导入路由对象,并且调用Vue.use(VueRouter)
-
第二布:创建路由实例,并且传入路由映射配置
- 第三步:在Vue实例中挂载创建的路由实例
-
使用vue-router步骤:
- 第一步:创建路由组件。
- 第二步:配置路由映射:组件和路径映射关系。
- 第三步:使用路由:通过
<router-link>
和<router-view>
演示
- 首先,我们创建完项目,将其中默认文件都删除掉,我们再演示router的使用,此时页面应该为空白:
- 我们创建项目时,选择了vue-router,就相当于帮我们安装了vue-router这个插件了,我们就不需要通过npm再次安装。
- 在src下,创建一个router的文件夹,里面放关于的路由的配置,在router文件夹下,创建index.js文件:
- 在该index.js文件中完成相关配置:
- 创建对应组件:Home组件与About组件。
- 配置映射关系:使组件与路径映射:
- 通过
<router-link>
和<router-view>
使用:
<router-link>
:该标签是一个vue-router中已经内置的组件,他会被渲染成一个<a>
标签。<router-view>
:该标签会根据当前的路径,动态渲染出不同的组件。- 网页的其他内容,比如顶部的标题/导航,或者底部的一些版权信息等会和
<router-view>
处于同一个等级。 - 在路由切换时,切换的是
<router-view>
挂载的组件,其他内容不会发生改变。
- 网页的其他内容,比如顶部的标题/导航,或者底部的一些版权信息等会和
路由的默认路径
- 我们这里有一个不太好的实现:
- 默认情况下,进入网站的首页,我们希望
<router-view>
渲染首页的内容。 - 但是我们的实现中,默认没有显示首页组件,必须让用户点击才可以。
- 默认情况下,进入网站的首页,我们希望
- 如果可以让路径默认跳到首页,并且
<router-view>
渲染首页组件呢?- 非常简单,我们只需要配置多一个映射就可以了。
- 配置解析:
- 我们在routes中有配置了一个映射。
- path配置的是根路径:/
- redirect是重定向,也就是我们将根路径重定向到/home的路径下,这样就可以得到我们想要的结果了。
HTML5的history模式
- 我们前面说过改变路径的方式有两种:
- URL的hash
- HTML5的history
- 默认情况下,路径的改变使用的是URL的hash
- 如果希望使用HTML5的history模式,非常简单,进行如下配置即可:
- 效果:
router-link标签补充
-
在前面的
<router-link>
中,我们只使用了一个属性:to,用于指定跳转的路径。 -
<router-link>
还有一些其他属性:-
tag:tag可以执行
<router-link>
之后渲染成什么组件,比如下面的代码会被渲染成一个button元素,而不是a标签。<router-link to='/home' tag='button'></router-link>
-
replace:replace不会留下history记录,所以指定replace的情况下,后退键返回不能返回到上一个页面中。
-
active-class:当
<router-link>
对应的路由匹配成功时,会自动给当前元素设置一个router-link-active的class设置active-class可以修改默认的名称。- 在进行高亮显示的导航菜单或者底部tabbar时,会使用到该类。
- 但是通常不会修改类的属性,会直接使用默认的router-link-active即可。
-
通过代码修改路由
<template>
<div id="app">
<!-- <router-link to="/home">首页</router-link>
<router-link to="/about">关于</router-link> -->
<button @click="clickHome">首页</button>
<button @click="clickAbout">关于</button>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'App',
methods: {
clickHome() {
// 通过代码的方式修改路由 vue-router
this.$router.push('/home');
//或this.$router.replace()
},
clickAbout() {
this.$router.push('/about');
}
}
}
</script>
<style>
</style>
- 有时候,页面的跳转可能需要执行JavaScript代码,这个时候,就可以使用第二种跳转方式了。
动态路由
- 我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件。例如,我们有一个
User
组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。 - 那么,我们可以在
vue-router
的路由路径中使用“动态路径参数”(dynamic segment) 来达到这个效果。
路由懒加载(官方)
-
当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。
-
官方在说什么呢?
- 首先,我们知道路由中通常会定义很多不同的页面。
- 这个页面最后被打包在那里呢?一般情况下,是放在一个js文件中。
- 但是,页面这么多放在一个js文件中,必然会造成这个页面非常大。
- 如果我们一次性从服务器请求下来这个页面,可能需要花费一定的时间,甚至用户的电脑上还会出现短暂的空白。
- 如何避免这种情况呢?使用路由的懒加载就可以了。
-
路由懒加载做了什么?
- 路由懒加载的主要作用就是将路由对应的组件打包成一个个的js代码块。
- 只有在这个路由被访问到的时候,才加载对应的组件。
-
首先,可以将异步组件定义为返回一个 Promise 的工厂函数 (该函数返回的 Promise 应该 resolve 组件本身):
const Foo = () => Promise.resolve({
/* 组件定义对象 */ })
- 第二,在 Webpack 2 中,我们可以使用动态 import语法来定义代码分块点 (split point):
import('./Foo.vue') // 返回 Promise
-
注意
- 如果您使用的是 Babel,你将需要添加
syntax-dynamic-import
插件,才能使 Babel 可以正确地解析语法。
- 如果您使用的是 Babel,你将需要添加
-
结合这两者,这就是如何定义一个能够被 Webpack 自动代码分割的异步组件。
const Foo = () => import('./Foo.vue')
- 在路由配置中什么都不需要改变,只需要像往常一样使用
Foo
:
const router = new VueRouter({
routes: [
{
path: '/foo', component: Foo }
]
})
把组件按组分块把组件按组分块
- 有时候我们想把某个路由下的所有组件都打包在同个异步块 (chunk) 中。只需要使用 命名 chunk,一个特殊的注释语法来提供 chunk name (需要 Webpack > 2.4)。
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')
- Webpack 会将任何一个异步模块与相同的块名称组合到相同的异步块中。
打包文件解析
- 我们在之前的项目中运行npm run build打包文件,出现:
懒加载使用
- 使用懒加载方式导入文件,再次打包文件:
vue-router嵌套路由
认识嵌套路由
- 嵌套路由是一个很常见的功能
- 比如在home页面中,我们希望通过home/news和home/message访问一些内容。
- 一个路径映射一个组件,访问这两个路径也会分别渲染两个组件。
嵌套路由的使用
- 首先我们创建两个组件HomeNews和HomeMessage:
- 在index.js中懒加载导入这两个组件,并在Home组件下使用children属性将两个组件配置好。
- 在Home组件中设置
<router-link>
和<router-view>
:
- 效果:
vue-router参数传递
-
当我们从一个页面跳转到另一个页面的时候,很有可能需要给我们传递一些参数。
-
传递参数主要有两种方式:params和query
-
params类型(上方动态路由):
- 配置路由格式:/router/:id
- 传递的方式:在path后面跟上对应的值
- 传递后形成的路径:/router/123,/router/abc
-
query的类型:
- 配置路由格式:/router,也就是普通配置
- 传递的方式:对象中使用query的key: value作为传递方式
- 传递后形成的路径:/router?id=123,/router?id=abc
演示query类型:
- 一般大量数据由query传递。
vue-router导航守卫
为什么要使用导航守卫?
-
我们来考虑一个需求:在一个SPA应用中,如何改变网页的标题呢?
- 网页标题是通过
<title>
来显示的,但是SPA只有一个固定的HTML,切换不同的页面时,标题并不会改变。 - 但是我们可以通过JavaScript来修改
<title>
的内容,window.document.title = '新的标题'
。 - 那么在Vue项目中,在哪里修改?什么时候修改比较合适呢?
- 网页标题是通过
-
普通的修改方式:
- 我们比较容易想到的修改标题的位置时每一个路由对应的组件.vue文件中。
- 通过mounted声明周期函数,执行对应的代码进行修改即可。
- 但是当页面比较多时,这种方式不容易维护(因为需要在多个页面执行类似的代码)
-
有没有更好的方法呢?使用导航守卫即可。
-
什么是导航守卫?
- vue-router提供的导航守卫只要用来监听路由的进入和离开的。
- vue-router提供了beforeEach和afterEach的钩子函数,它们会在路由即将改变前和改变后触发。
导航守卫使用
- 我们可以利用beforeEach来完成标题的修改。
- 首先,我们可以在钩子当中定义一些标题,可以利用meta来定义。
- 其次,利用导航守卫,修改我们的标题。
- 导航钩子的三个参数解析:
- to:即将要进入的目标的路由对象。
- form:当前导航即将要离开的路由对象。
- next:调用该方法后,才能进入下一个钩子。
- 补充一:如果是后置钩子,也就是afterEach,不需要主动调用next()函数。
- 补充二:上面我们使用的导航守卫,被称之为全局守卫。
- 路由独享的守卫。
- 组件内的守卫。
回顾
Vue笔记一——Vue安装与体验
Vue笔记二——Vue声明周期与模板语法
Vue笔记三——计算属性(computed)
Vue笔记四——事件监听的使用
Vue笔记五——条件判断与循环遍历
Vue笔记六——书籍购物车案例
Vue笔记七——v-model表单输入绑定详细介绍
Vue笔记八——关于组件不可不知的知识!
Vue笔记九——slot插槽的使用
Vue笔记十——webpack敲重点!!!(详解)
Vue笔记十一——Vue CLI相关