Vue-Router
一. 认识路由
1.什么是路由(理解)
- 路由解释
- 路由(routing)就是通过互联的网络把信息从源地址传输到目的地址的活动
- 路由中有一个非常重要的概念叫路由表
- 路由表本质上就是一个映射表, 决定了数据包的指向
- 路由器
- 路由器提供了两种机制: 路由和转送.
- 路由是决定数据包从来源到目的地的路径
- 转送将输入端的数据转移到合适的输出端
- 路由器提供了两种机制: 路由和转送.
路由是根据不同的ur地址展示不同的内容或页面;
路由是一个比较广义和抽象的概念, 路由的本质就是对应关系
2.后端路由阶段
- 在早期的网站开发整个HTML页面是由服务器来渲染的
- 服务器直接将渲染好对应的HTML页面, 响应给客户端展示
- 后端路由
- 浏览器在地址栏中切换不同的url时, 每次都向后台服务器发出请求, 服务器响应请求
- 在后台拼接html文件传给前端显示, 返回不同的页面
- 意味着浏览器会刷新页面,网速慢的话说不定屏幕全白再有新内容。后端路由的另外一个极大的问题就是 前后端不分离
后端路由的缺点
- 整个页面的模块由后端人员来编写和维护的, 不易维护
- 通常情况下HTML代码和以及对应的后端逻辑代码会混在一起, 编写和维护都是非常糟糕的事情
3.前端路由阶段
- 前后端分离阶段:
- 随着 Ajax 出现, 有了前后端分离的开发模式
- 后端只提供 API 来返回数据, 前端通过 Ajax 获取数据, 通过 JS 将数据渲染到页面中
- 这样做最大优点就是前后端责任清晰, 后端专注于数据上, 前端专注于交互和可视化上
- 并且移动端 (ISO/Android) 出现后, 后端不需要进行任何处理, 依然使用之前一套 API 即可
- 什么是SPA
- SPA是 single page web application 的简称, 译为单页Web应用
- 简单说 SPA 就是一个 web 项目只有一个 html 页面, 一旦页面加载完成, SPA 不会因为用户的操作进行页面的重新加载或跳转
- 取而代之的是利用 JS 动态的变换 html 的内容, 从而模拟多个视图间跳转
- 单页面富应用 (SPA)
- 其实SPA最主要的特点就是在前后端分离的基础上加了一层前端路由
- 也就是前端来维护一套路由规则
- 前端路由的核心是什么呢?
- 改变URL, 但是页面不进行整体的刷新
二. 前端路由的规则
1.URL的hash
- URL的hash也就是锚点(#), 本质上是改变window.location的href属性
- 我们可以直接赋值
location.hash
改变href, 但是页面不发生刷新
2.HTML5的history模式
- history接口是HTML5新增的, 它有五种模式改变URL而不刷新页面
history.pushState()
- 类似: 进栈出栈, 先进后出
history.replaceState()
- 替换URL, 没有回退
history.back()
- 回退到上一次的URL
history.forward()
- 前进上一次的URL
history.go(Number)
Number
: 前进或回退到指定的URL
三. Vue-Router基础
1.认识vue-router
- vue-router是Vue.js官方的路由插件, 它和vue.js是深度继承的, 用于构建单页面应用 (官方文档)
- vue-router是基于路由和组件的
- 路由用于设定访问路径, 将路径和组件映射起来
- 在vue-router的单页面应用中, 页面的路径的改变就是组件的切换
2.安装与使用vue-router
-
步骤一: npm安装
npm install vue-router --save
-
步骤二: 在模块工程中使用它(因为是一个插件, 所以通过
Vue.use()
来安装路由功能)
① 导入路由对象, 并且调用Vue.use(VueRouter)
安装路由功能
② 创建路由实例, 并传入路由映射配置
③ 在主入口文件: 引入创建的路由实例, Vue实例中挂载路由实例
1.配置Vue-Router (图示)- 步骤三: 使用
vue-router
-
-
创建路由组件
-
配置路由映射(组件和路径映射的关系)
-
使用路由
<router-link to="/path">
和<router-view>
-
3.路由组件详解
-
<router-link>
: 该标签是已经内置全局的组件, 它会被渲染成一个<a>
标签to="path"
: 该属性会被渲染为href
属性to="path"
: 属性的值会渲染为 # 开头的hash
地址path
: 在路由中配置的 path 路径
-
<router-view>
: 该标签会根据当前的路径, 动态渲染出相对应的组件 -
在路由切换时, 切换的是
<router-view>
挂载的组件, 其他内容不会发生改变
四. 路由配置其他补充
1.路由的默认路径
场景: 进入网站首页, 希望<router-view>
渲染首页的内容
- 在路由规则中添加默认路径的重定向
const routes = [ { // 配置默认路径 path: '/', // 重定向到/home路径 redirect: '/home' } ]
2.路径的History模式
场景: 页面显示的URL, 不希望是哈希值带 #/home
, 希望显示正常的URL: /home
- 在
VueRouter
实例option
中设置mode
为history
模式即可
// 创建VueRouter对象 const router = new VueRouter({ routes,// 路由规则 mode: 'history'// URL显示的模式 })
3.router-link和配置路由的属性补充
<route-link>
其他的属性
tag=""
: tab可以指定<router-link>
组件渲染成什么元素replace
: 没有回退history记录, 前进没有效果active-class=""
: 当<router-link>
对应的路径匹配成功时, 会自动给当前元素添加一个router-link-active
的class
, 设置active-class
可以更改默认的名称
<!-- tag: 指定<router-link>组件渲染成什么元素 --> <!-- replace: 没有history记录,前后键没有用 --> <!-- active-class: 修改匹配成功默认添加的class类名 --> <router-link to="/home" tag="button" replace active-class="active">首页</router-link> <router-link to="/about" tag="button" replace active-class="active">关于页面</router-link>
- 配置路由的属性:
linkActiveClass
- 作用: 当
<router-link>
对应的路径匹配成功时, 设置默认添加的类名
- 作用: 当
const router = new VueRouter({ routes,// 路由的映射规则 mode: 'history',// 模式 linkActiveClass: 'active'// 设置默认匹配添加地类 })
4.编程式导航
<router-link>
全局组件, 来跳转URL
this.$router.push('path')
: 来实现跳转URL, 有回退history记录this.$router.replace('path')
: 来实现跳转URL, 没有回退history记录
methods: { home() { // 没有使用<router-link>全局组件,来跳转URL,如何实现 // this.$router.push('/home') // 有回退记录 this.$router.replace('/home') // 没有回退记录 }, about() { // this.$router.push('/about') this.$router.replace('/about') } }
5.动态路由匹配
-
某些情况, 我们需要动态的来设置path路径, 比如进入用户页面, 希望显示的是如下路径
- /user/aaa 或 /user/bbb
- 除了有前面的 /user 之外, 后面还跟上了用户的ID
- 这种 path 和 Component 的匹配关系, 称之为动态路由(也是路由传递数据的一种方式)
-
动态路由匹配步骤
- 1.配置动态路由参数
const routes = [{ path: '/user/:userId', component: User }]
-
- 2.在APP.vue组件中传递参数
- 3.路由组件中通过
$route.params
获取路由参数
图示
五. 路由懒加载
1.认识路由懒加载
- 官方解释
- 当打包构建应用时, JavaScript包会变的非常大, 影响页面加载
- 如果我们能把不同路由对应的组件分割成不同的代码块, 然后当路由被访问的时候才加载对应组件, 这样就更高效了
- 为什么使用路由懒加载?
- 我们打包后的文件一般情况都是放在一个js文件当中, 必然这个文件会非常大
- 如果我们一次性从网络请求下来这个文件, 可能花费很长时间, 甚至浏览器出现短暂白屏状况
- 如何避免这种情况: 使用路由懒加载就可以了
- 路由懒加载做了什么?
- 路由懒加载的主要作用就是: 将路由对应的组件打包成一个个的js代码块
- 只有这个路由被访问到的时候, 才加载对应的组件
2.使用路由懒加载
- 方式一: 结合Vue的异步组件和Webpack的代码分析
- const Home = resolve => { require.ensure(['../components/Home.vue'], () => { resolve(require('../components/Home.vue')) })};
- 方式二: AMD写法
- const About = resolve => require(['../components/About.vue'], resolve);
- 方式三: ES6中, 我们有更加简单的写法来组织Vue异步组件和Webpack的代码分隔
- const Home = () => import('../components/Home.vue')
- 打包后效果图
六. 路由嵌套
1.认识嵌套路由
- 在 home 页面中, 我们通过 /home/news 和 /home/message 访问一些内容
- 在一个路径映射另一个组件, 访问这两个路径也会分别渲染两个组件
- 路径和组件的关系如下:
2.嵌套路由实现
- 1.创建组件
- 2.在路由映射规则中, 配置嵌套路由:
children: [{},{}]
- 3.在需要嵌套该组件的页面中, 使用 router-link 和 router-view
3.嵌套路由的默认路径
- 嵌套的路由也可以设置默认路径
-
const routes = [ { path: '/home', component: Home, // 配置嵌套路由 children: [ { // 嵌套路由的默认路径 path: '', redirect: 'news' }, { path: 'news', component: News }, { path: 'message', component: Message }] }]
七. query获取参数
1.query获取
- 1.创建新的组件 Profile.vue
- 2.配置路由映射
- 3.在 APP.vue 添加跳转的 <router-link>
<!-- 1. APP.vue 参数的传递 --> <router-link :to="{path: '/profile',query: { name: 'wuyifan', age: 18, height: 1.88}}">档案</router-link> <!-- 2. Profile.vue 获取query参数 --> <h3>{{$route.query}}</h3>
图示
2.传递参数的方式
- 传递参数主要有两种类型: params和query
- params
- 配置路由
path
:/user/:userId
- 传递的方式: 在path后面拼接上需要传递的值
- 获取传递的参数:
$route.params.userId
- 配置路由
- query
- 配置路由
path
:/profile
(普通配置) - 传递的方式:
{path: '/profile', query: {name: 'yifan'} }
- 获取传递的参数:
$route.query.name
- 配置路由
<router-link>
来实现跳转-
this.$router.push({ path: '/profile', query: { name: 'yifan', age: 18, height: 1.88 } })
3. router 和 route的区别
$router
和$route
区别$router
是VueRouter实例, 对路径相关导航操作route
是当前path映射的组件对象(当前活跃的路由对象), 可以获取path, query
参数等
八. 导航守卫⚔
1.认识导航守卫
官方解释: vue-router
提供的导航守卫主要用来通过跳转或取消的方式导航守卫
- 导航守卫就是路由跳转过程中的一些钩子函数, 路由跳转是一个大的过程, 这个大的过程前后中等等细小的过程, 在每个过程都有一个函数, 这个函数能够让你操作一些其他的事情, 这就是导航守卫
vue-router
提供了beforeEach
和afterEach
的钩子函数, 它们会在路由即将改变前和改变后触发
全局钩子函数
可以直接在路由配量文件router.js里编写代码逻辑, 可以做一些全局性的路由拦截// 全局前置守卫router.beforeEach((to, from, next) => { // to: Route:即将要进入的目标路由对象 // from: Route:当前导航正要离开的路由 // 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是confirmed (确认的) next(); }); // 全局后置守卫router.afterEach((to, from) => { console.log(to.path); });
2.导航守卫使用
- 考虑一个需求: 在一个SPA应用中, 如何修改网页标题
- 第一应该想到在每一个路由对应的组件.vue文件中, 通过
mounted
生命周期函数, 对标题修改 - 但是当页面比较多是, 这种方式不易维护(因为需要在多个页面执行类似的代码)
- 有没有更好的方法呢? 使用导航守卫即可
- 第一应该想到在每一个路由对应的组件.vue文件中, 通过
- 在路由配置文件中使用导航守卫, 修改网页标题
// 在钩子当中定义一些标题, 可以利用meta来定义const routes = [ { path: '/user/:userId', component: User, meta: { title: '用户' } }, { path: '/profile', component: Profile, meta: { title: '档案' } }] // ------导航守卫(guard)----------- router.beforeEach((to, from, next) => { // 从from跳转到to // from: 将要进行跳转的当前$route对象 (跳转前的一些操作) // to: 跳转后$route对象 (跳转后的一些操作) // next(): 调用该方法后, 才能进入下一个钩子 document.title = to.matched[0].meta.title; next() })
3.全局后置钩子
你也可以注册全局后置钩子, 然而和守卫不同的是, 这些钩子不会接受next
函数也不会改变导航本身
router.afterEach((to, from) => { // ... })
4.路由独享钩子函数
可以做一些单个路由的跳转拦截。在配量文件编写代码即可
const router = new VueRouter({ routes: [ { path: '/foo', component: Foo, beforeEnter: (to, from, next) => { // ... } } ]})
5.组件内钩子函数
更细粒度的路由拦截, 只针对一个进入某一个组件的拦截
const Foo = { template: `...`, beforeRouteEnter (to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `this` // 因为当钩子执行前,组件实例还没被创建 }, beforeRouteUpdate (to, from, next) { // 在当前路由改变,但是该组件被复用时调用 // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。 // 可以访问组件实例 `this` }, beforeRouteLeave (to, from, next) { // 导航离开该组件的对应路由时调用 // 可以访问组件实例 `this` } }
钩子函数使用场景
九. keep-alive组件
1.页面缓存
- 在Vue构建的单页面应用(SPA)中, 路由模块一般使用
vue-router
vue-router
不保存组件被切换的状态, 它进行push或replcae时, 旧组件会被销毁, 新组建会被创建, 再走一遍完整的生命周期- 但是有的时候, 我们有一些需求,: 比如返回到跳转前用户点击的列表页面, 但是当我们返回的时候没有之前的记录,对于这种页面缓存需求, 我们可以使用
keep-alive
组件来解决
2.keep-alive组件
keep-alive
是 Vue 内置的一个组件, 可以使被包含的组件保留状态, 或避免重新渲染- 两个非常重要的属性:
inclue
: 值是字符串或正则表达, 只有匹配的组件会被缓存exclue
: 值是字符串或正则表达, 任何匹配的组件都不会被缓存- 千万注意: 字符串匹配的是Vue组件中name属性, 如果没有配置
name
属性 keep-alive 将不会生效
- 使用
keep-alive
: 在keep-alive
包裹中的视图组件都会被缓存 -
<!-- Profile,User是 Vue 组件中的name属性(千万注意,如果没有配置将不会生效) --> <keep-alive exclude="Profile,User"> <router-view></router-view> </keep-alive>
另外:activated,deactivated这两个生命周期函数一定是要在使用了keep-alive组件后才会有的,否则则不存在
作者:风不识途
链接:https://juejin.im/post/6857124868359061512
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。