引言

keep-alive可以实现组件缓存,当组件切换时不会对当前组件进行卸载。

主要是有include、exclude、max三个属性;

前两个属性允许keep-alive有条件的进行缓存;

max可以定义组件最大的缓存个数,如果超过了这个个数的话,在下一个新实例创建之前,就会将以缓存组件中最久没有被访问到的实例销毁掉。

两个生命周期activated/deactivated,用来得知当前组件是否处于活跃状态。

Home.vue

<template>
  <div class="hello">
    <h1>你怎么还在学习?🗑️</h1>
    <input placeholder="输入框" />
    <router-link to="/about">我的人生理想</router-link>
  </div>
</template>

About.vue

<template>
  <div class="hello">
    <h1>我想取老婆 🐜</h1>
  </div>
</template>

App.vue

<template>
  <div id="app">
    <router-view/>
  </div>
</template>
<script>
import Home from './views/Home.vue'
import About from './views/About.vue'
export default {
  components: {
    Home,
    About,
  }
}
</script>

你在输入框中输入信息,点击跳转到另外一个页面后,回到该页面,你会发现,输入框中的文字消失了。怎么办勒

使用 keep-alive 包裹 router-view,同时指定需要缓存的组件名称。(PS:请在要缓存的组件中,写明 name 属性,并赋值。不然缓存不生效)

Home.vue

App.vue

<template>
  <div id="app">
    <keep-alive include="Home">
      <router-view/>
    </keep-alive>
  </div>
</template>
<script>
import Home from './views/Home.vue'
import About from './views/About.vue'
export default {
  components: {
    Home,
    About,
  }
}
</script>

结合 Router,缓存页面

router.js

import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
Vue.use(Router)
export default new Router({
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home,
      // 需要被缓存
      meta: {
        keepAlive: true
      }
    },
    {
      path: '/about',
      name: 'about',
      component: () => import('./views/About.vue')
    },
  ]
})

Home.vue

<script>
export default {
  name: "Home",
  beforeRouteLeave(to, from, next) {
    to.meta.keepAlive = true;
    next();
  },
};
</script>

App.vue

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

剩下的一些其他特性,可以自行前往官网查阅 cn.vuejs.org/v2/api/#kee…

keep-alive 原理

keep-alive中运用了LRU(Least Recently Used)算法。

  • 获取 keep-alive 包裹着的第一个子组件对象及其组件名; 如果 keep-alive 存在多个子元素,keep-alive 要求同时只有一个子元素被渲染。所以在开头会获取插槽内的子元素,调用 getFirstComponentChild 获取到第一个子元素的 VNode
  • 根据设定的黑白名单(如果有)进行条件匹配,决定是否缓存。不匹配,直接返回组件实例(VNode),否则开启缓存策略。
  • 根据组件ID和tag生成缓存Key,并在缓存对象中查找是否已缓存过该组件实例。如果存在,直接取出缓存值并更新该key在this.keys中的位置(更新key的位置是实现LRU置换策略的关键)。
  • 如果不存在,则在this.cache对象中存储该组件实例并保存key值,之后检查缓存的实例数量是否超过max设置值,超过则根据LRU置换策略删除最近最久未使用的实例(即是下标为0的那个key)。最后将该组件实例的keepAlive属性值设置为true
var KeepAlive = {
  name: 'keep-alive',
  // 抽象组件
  abstract: true,
  // 接收的参数
  props: {
    include: patternTypes,
    exclude: patternTypes,
    max: [String, Number]
  },
  // 创建缓存表
  created: function created () {
    this.cache = Object.create(null);
    this.keys = [];
  },
  destroyed: function destroyed () {
    for (var key in this.cache) {
      pruneCacheEntry(this.cache, key, this.keys);
    }
  },
  mounted: function mounted () {
    var this$1 = this;
    this.$watch('include', function (val) {
      pruneCache(this$1, function (name) { return matches(val, name); });
    });
    this.$watch('exclude', function (val) {
      pruneCache(this$1, function (name) { return !matches(val, name); });
    });
  },
  render: function render () {
    var slot = this.$slots.default;
    // 获取 `keep-alive` 包裹着的第一个子组件对象及其组件名; 
    // 如果 keep-alive 存在多个子元素,`keep-alive` 要求同时只有一个子元素被渲染。
    // 所以在开头会获取插槽内的子元素,
    // 调用 `getFirstComponentChild` 获取到第一个子元素的 `VNode`。
    var vnode = getFirstComponentChild(slot);
    var componentOptions = vnode && vnode.componentOptions;
    if (componentOptions) {
      // check pattern
      var name = getComponentName(componentOptions);
      var ref = this;
      var include = ref.include;
      var exclude = ref.exclude;
      // 根据设定的黑白名单(如果有)进行条件匹配,决定是否缓存。   
      if (
        // not included
        (include && (!name || !matches(include, name))) ||
        // excluded
        (exclude && name && matches(exclude, name))
      ) {
      // 不匹配,直接返回组件实例(`VNode`),否则开启缓存策略。
        return vnode
      }
      var ref$1 = this;
      var cache = ref$1.cache;
      var keys = ref$1.keys;
      // 根据组件ID和tag生成缓存Key
      var key = vnode.key == null
        ? componentOptions.Ctor.cid   (componentOptions.tag ? ("::"   (componentOptions.tag)) : '')
        : vnode.key;
      if (cache[key]) {
      // 并在缓存对象中查找是否已缓存过该组件实例。如果存在,直接取出缓存值
        vnode.componentInstance = cache[key].componentInstance;
        // 并更新该key在this.keys中的位置(更新key的位置是实现LRU置换策略的关键)。
        remove(keys, key);
        keys.push(key);
      } else {
       // 如果不存在,则在this.cache对象中存储该组件实例并保存key值,
        cache[key] = vnode;
        keys.push(key);
        // 之后检查缓存的实例数量是否超过max设置值,超过则根据LRU置换策略删除最近最久未使用的实例
        if (this.max && keys.length > parseInt(this.max)) {
          pruneCacheEntry(cache, keys[0], keys, this._vnode);
        }
      }
		// 最后将该组件实例的keepAlive属性值设置为true。
      vnode.data.keepAlive = true;
    }
    return vnode || (slot && slot[0])
  }
};

以上就是五分钟理解keep alive用法及原理的详细内容,更多关于keep alive用法原理的资料请关注Devmax其它相关文章!

五分钟理解keep alive用法及原理的更多相关文章

  1. 如何在Android中设置keepalive超时?

    看起来我可以这样做,如果我使用NDK,但我想将此代码分发为jar,所以这对我来说并不理想.解决方法这可能是一个非常明显的答案[即它不是你特定案例的选项]但是你当然可以通过每10分钟发送1个丢弃字节来实现你自己的keepalive.

  2. VUE响应式原理的实现详解

    这篇文章主要为大家详细介绍了VUE响应式原理的实现,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

  3. 五分钟理解keep alive用法及原理

    这篇文章主要为大家介绍了keep alive用法及原理示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. PHP架构及原理知识点详解

    这篇文章主要介绍了PHP架构及原理知识点以及相关实例讲解,需要的朋友们参考下。

  5. DialogFragment运行原理及使用方法详解

    这篇文章主要介绍了DialogFragment运行原理及使用方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

  6. ES6的Promise用法详解

    本文详细讲解了ES6的Promise用法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  7. React Hook用法示例详解(6个常见hook)

    这篇文章主要介绍了React Hook用法详解(6个常见hook),本文通过实例代码给大家介绍了6个常见hook,需要的朋友可以参考下

  8. vue3.0响应式函数原理详细

    这篇文章主要介绍了vue3.0响应式函数原理,Vue3的响应式系统可以监听动态添加的属性还可以监听属性的删除操作,以及数组的索引以及length属性的修改操作。另外Vue3的响应式系统还可以作为模块单独使用。下面更多介绍,需要的小伙伴可以才可以参考一下

  9. 一文详解Mybatis-plus的介绍与使用

    Mybatis-Plus 是 MyBatis 的一个增强工具,专门针对于传统MyBatis开发中sql需要手动进行映射配置繁琐缺点的一款框架技术。本文将为大家详细讲讲Mybatis-plus的介绍与使用,感兴趣的可以了解一下

  10. 一文搞懂Spring循环依赖的原理

    这篇文章将用实例来为大家详细介绍@Autowired解决循环依赖的原理,文中的示例代码讲解详细,对我们学习Spring有一定帮助,感兴趣的可以学习一下

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部