深入理解Vue keep-alive及实践总结


Posted in Javascript onAugust 21, 2019

什么是 keep-alive

在平常开发中,有部分组件没有必要多次初始化,这时,我们需要将组件进行持久化,使组件的状态维持不变,在下一次展示时,也不会进行重新初始化组件。

也就是说,keepalive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染 。也就是所谓的组件缓存
<keep-alive>是Vue的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM。

<keep-alive> 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 <transition> 相似,<keep-alive> 是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中。

prop:

  • include: 字符串或正则表达式。只有匹配的组件会被缓存。
  • exclude: 字符串或正则表达式。任何匹配的组件都不会被缓存。

keep-alive的声明周期执行

页面第一次进入,钩子的触发顺序

created-> mounted-> activated,退出时触发 deactivated

当再次进入(前进或者后退)时,只触发 activated

事件挂载的方法等,只执行一次的放在 mounted 中;组件每次进去执行的方法放在 activated 中;

基本用法

<!--被keepalive包含的组件会被缓存-->
<keep-alive>
  <component><component />
</keep-alive>

被keepalive包含的组件不会被再次初始化,也就意味着不会重走生命周期函数
但是有时候是希望我们缓存的组件可以能够再次进行渲染,这时 Vue 为我们解决了这个问题
被包含在 keep-alive 中创建的组件,会多出两个生命周期的钩子: activated 与 deactivated:

  • activated 当 keepalive 包含的组件再次渲染的时候触发
  • deactivated 当 keepalive 包含的组件销毁的时候触发

keepalive是一个抽象的组件,缓存的组件不会被 mounted,为此提供activated和deactivated钩子函数

参数理解

keepalive 可以接收3个属性做为参数进行匹配对应的组件进行缓存:

  • include 包含的组件(可以为字符串,数组,以及正则表达式,只有匹配的组件会被缓存)
  • exclude 排除的组件(以为字符串,数组,以及正则表达式,任何匹配的组件都不会被缓存)
  • max 缓存组件的最大值(类型为字符或者数字,可以控制缓存组件的个数)

注:当使用正则表达式或者数组时,一定要使用 v-bind

<!-- 将(只)缓存组件name为a或者b的组件, 结合动态组件使用 -->
<keep-alive include="a,b">
 <component></component>
</keep-alive>

<!-- 组件name为c的组件不缓存(可以保留它的状态或避免重新渲染) -->
<keep-alive exclude="c"> 
 <component></component>
</keep-alive>

<!-- 使用正则表达式,需使用v-bind -->
<keep-alive :include="/a|b/">
 <component :is="view"></component>
</keep-alive>

<!-- 动态判断 -->
<keep-alive :include="includedComponents">
 <router-view></router-view>
</keep-alive>

<!-- 如果同时使用include,exclude,那么exclude优先于include, 下面的例子只缓存a组件 -->
<keep-alive include="a,b" exclude="b"> 
 <component></component>
</keep-alive>

<!-- 如果缓存的组件超过了max设定的值5,那么将删除第一个缓存的组件 -->
<keep-alive exclude="c" max="5"> 
 <component></component>
</keep-alive>

遇见 vue-router 结合router使用,缓存部分页面

所有路径下的视图组件都会被缓存

<keep-alive>
  <router-view>
    <!-- 所有路径匹配到的视图组件都会被缓存! -->
  </router-view>
</keep-alive>

如果只想要router-view里面的某个组件被缓存,怎么办?

  • 使用 include/exclude
  • 使用 meta 属性

1、用 include (exclude例子类似)

缺点:需要知道组件的 name,项目复杂的时候不是很好的选择

<keep-alive include="a">
  <router-view>
    <!-- 只有路径匹配到的 include 为 a 组件会被缓存 -->
  </router-view>
</keep-alive>

2、使用 meta 属性

优点:不需要例举出需要被缓存组件名称

使用$route.meta的keepAlive属性:

<keep-alive>
  <router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>

需要在router中设置router的元信息meta:

//...router.js
export default new Router({
 routes: [
  {
   path: '/',
   name: 'Hello',
   component: Hello,
   meta: {
    keepAlive: false // 不需要缓存
   }
  },
  {
   path: '/page1',
   name: 'Page1',
   component: Page1,
   meta: {
    keepAlive: true // 需要被缓存
   }
  }
 ]
})

【加盐】使用 router.meta 拓展

假设这里有 3 个路由: A、B、C。

需求:

  • 默认显示 A
  • B 跳到 A,A 不刷新
  • C 跳到 A,A 刷新

实现方式

在 A 路由里面设置 meta 属性:

{
    path: '/',
    name: 'A',
    component: A,
    meta: {
      keepAlive: true // 需要被缓存
    }
}

在 B 组件里面设置 beforeRouteLeave:

export default {
    data() {
      return {};
    },
    methods: {},
    beforeRouteLeave(to, from, next) {
       // 设置下一个路由的 meta
      to.meta.keepAlive = true; // 让 A 缓存,即不刷新
      next();
    }
};

在 C 组件里面设置 beforeRouteLeave:

export default {
    data() {
      return {};
    },
    methods: {},
    beforeRouteLeave(to, from, next) {
      // 设置下一个路由的 meta
      to.meta.keepAlive = false; // 让 A 不缓存,即刷新
      next();
    }
};

这样便能实现 B 回到 A,A 不刷新;而 C 回到 A 则刷新。

防坑指南

1.keep-alive 先匹配被包含组件的 name 字段,如果 name 不可用,则匹配当前组件 components 配置中的注册名称。
2.keep-alive 不会在函数式组件中正常工作,因为它们没有缓存实例。
3.当匹配条件同时在 include 与 exclude 存在时,以 exclude 优先级最高(当前vue 2.4.2 version)。比如:包含于排除同时匹配到了组件A,那组件A不会被缓存。
4.包含在 keep-alive 中,但符合 exclude ,不会调用 activated 和 deactivated。

实现前进刷新,后退不刷新

感谢 iceuncle 分享的 《vue实现前进刷新,后退不刷新》。

总结

路由大法不错,不需要关心哪个页面跳转过来的,只要 router.go(-1) 就能回去,不需要额外参数。

在非单页应用的时候,keep-alive 并不能有效的缓存了= =

keep-alive生命周期钩子函数:activated、deactivated

使用<keep-alive>会将数据保留在内存中,如果要在每次进入页面的时候获取最新的数据,需要在activated阶段获取数据,承担原来created钩子中获取数据的任务。

附录

生命周期函数:就是vue在某个时间段会自动执行的函数

  • beforeCreate(){}在执行的时候,data还有methods都没有被初始化
  • created(){} data还有methods都被初始化好了,如果要调用 methods 方法或者操作 data 里面的数据,最早只能在 created 里面进行操作。
  • beforeMount(){} 表示模板已经在内存中编辑完成了,但是尚未渲染到模板页面中。即页面中的元素,没有被真正的替换过来,只是之前写的一些模板字符串。
  • mounted(){} 表示内存中模板已经真实的挂载到页面中去了,用户可以看到渲染好的界面了

注意这是一个生命周期函数的最后一个函数了,执行完这个函数表示 整个vue实例已经初始化完成了,组件脱离了创建阶段,进入运行阶段。

下面是运行期间的两个生命周期函数的钩子:

beforeUpdate(){} 表示我们的界面还没更新 但是data里面的数据是最新的。即页面尚未和最新的data里面的数据保持同步。

update(){} 表示页面和data里面的数据已经包吃同步了 都是最新的。

beforeDestory(){} 当执行这个生命周期钩子的时候 vue的实例从运行阶段进入销毁阶段 此时实例身上的data 还有 methods处于可用的状态。

Destoryed(){} 表示组件已经完全被销毁了 组件中所有的实例方法都是不能用了

参考:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript 密码强弱度检测万能插件
Feb 25 Javascript
jquery ajax 同步异步的执行示例代码
Jun 23 Javascript
JavaScript 函数惰性载入的实现及其优点介绍
Aug 12 Javascript
JS控制阿拉伯数字转为中文大写示例代码
Sep 04 Javascript
JavaScript中Function函数与Object对象的关系
Dec 17 Javascript
浅谈jQuery绑定事件会叠加的解决方法和心得总结
Oct 26 Javascript
Easy UI动态树点击文字实现展开关闭功能
Sep 30 Javascript
详解Angular模板引用变量及其作用域
Nov 23 Javascript
VUE项目初建和常见问题总结
Sep 12 Javascript
vue 实现LED数字时钟效果(开箱即用)
Dec 08 Javascript
基于javascript的无缝滚动动画实现2
Aug 07 Javascript
三种方式清除vue路由跳转router-link的历史记录
Apr 10 Vue.js
vue element 生成无线级左侧菜单的实现代码
Aug 21 #Javascript
微信小程序仿今日头条导航栏滚动解析
Aug 20 #Javascript
Vue中axios的封装(报错、鉴权、跳转、拦截、提示)
Aug 20 #Javascript
Vue formData实现图片上传
Aug 20 #Javascript
Angular8 Http拦截器简单使用教程
Aug 20 #Javascript
vue实现axios图片上传功能
Aug 20 #Javascript
扫微信小程序码实现网站登陆实现解析
Aug 20 #Javascript
You might like
让你的网站首页自动选择语言转跳
2006/12/06 PHP
PHP验证码类代码( 最新修改,完全定制化! )
2010/12/02 PHP
解决phpmyadmin中缺少mysqli扩展问题的方法
2013/05/06 PHP
PHP中的类型约束介绍
2015/05/11 PHP
php自定义函数转换html标签示例
2016/09/29 PHP
借用Google的Javascript API Loader来加速你的网站
2009/01/28 Javascript
checkbox 复选框不能为空
2009/07/11 Javascript
JavaScript高级程序设计 学习笔记 js高级技巧
2011/09/20 Javascript
js导出table数据到excel即导出为EXCEL文档的方法
2013/10/10 Javascript
Node.js实现在目录中查找某个字符串及所在文件
2014/09/03 Javascript
关于延迟加载JavaScript
2015/05/05 Javascript
第二章之Bootstrap 页面排版样式
2016/04/25 Javascript
js删除数组元素、清空数组的简单方法(必看)
2016/07/27 Javascript
详解angularJS+Ionic移动端图片上传的解决办法
2017/09/13 Javascript
vue项目webpack中Npm传递参数配置不同域名接口
2018/06/15 Javascript
简述JS浏览器的三种弹窗
2018/07/15 Javascript
angular4应用中输入的最小值和最大值的方法
2019/05/17 Javascript
[57:53]DOTA2上海特级锦标赛主赛事日 - 2 败者组第二轮#3OG VS VP
2016/03/03 DOTA
[07:09]DOTA2-DPC中国联赛 正赛 Ehome vs Elephant 选手采访
2021/03/11 DOTA
python使用内存zipfile对象在内存中打包文件示例
2014/04/30 Python
Python手机号码归属地查询代码
2016/05/04 Python
Python如何快速实现分布式任务
2017/07/06 Python
Django查询数据库的性能优化示例代码
2017/09/24 Python
R语言 vs Python对比:数据分析哪家强?
2017/11/17 Python
python输入错误密码用户锁定实现方法
2017/11/27 Python
微信跳一跳辅助python代码实现
2018/01/05 Python
Python调用C语言的实现
2019/07/26 Python
HTML5的结构和语义(1):前言
2008/10/17 HTML / CSS
Otticanet美国:最顶尖的世界名牌眼镜, 能得到打折季的价格
2019/03/10 全球购物
最新大学毕业求职简历的自我评价
2013/10/18 职场文书
小学母亲节活动方案
2014/03/14 职场文书
护士求职信范文
2014/05/24 职场文书
工地安全标语
2014/06/07 职场文书
大跃进口号
2014/06/16 职场文书
HR必备:超全面的薪酬待遇管理方案!
2019/07/12 职场文书
介绍一下28个JS常用数组方法
2022/05/06 Javascript