首页前端开发VUEvue2.x中keep-alive源码解析(实例代码)

vue2.x中keep-alive源码解析(实例代码)

时间2024-02-11 03:32:03发布访客分类VUE浏览485
导读:收集整理的这篇文章主要介绍了vue2.x中keep-alive源码解析(实例代码 ,觉得挺不错的,现在分享给大家,也给大家做个参考。 目录一、前世尘缘二、keep-alive内置组件1....
收集整理的这篇文章主要介绍了vue2.x中keep-alive源码解析(实例代码),觉得挺不错的,现在分享给大家,也给大家做个参考。
目录
  • 一、前世尘缘
  • 二、keep-alive内置组件
    • 1.缓存动态组件
    • 2.缓存路由组件
    • 3.原理解析
  • 三、LRU算法

    一、前世尘缘

    vue中内置组件keep-alive的设计思想源于HTTP中的Keep-Alive模式,Keep-Alive模式避免频繁创建、销毁链接,允许多个请求和响应使用同一个HTTP链接。
    HTTP 1.0 中keep-alive默认是关闭的,需要在HTTP头加入"Connection: Keep-Alive",才能启用Keep-Alive;HTTP 1.1中默认启用Keep-Alive,如果加入"Connection: close ",才关闭。目前大部分浏览器都是用HTTP 1.1协议。

    二、keep-alive内置组件

    作用:动态切换组件时缓存组件实例,避免dom重新渲染。

    1.缓存动态组件

    当组件为componentOne时缓存该组件实例

    keep-alive :include="componentOne`" :exclude="componentTwo" :max="num">
             component :is="currentComponent">
        /component>
         /keep-alive>
        

    2.缓存路由组件

    注意缓存路由组件vue2.x与vue3.x有区别,vue2.x用法如下:

    keep-alive :include="componentOne`" :exclude="componentTwo" :max="num">
             router-view :is="currentComponent">
        /router-view>
         /keep-alive>
        

    vue3.x用法如下:

    router-view v-slot="{
     Component }
        ">
           keep-alive :include="includeList">
        	    component :is="Component"/>
           /keep-alive>
        /router-view>
        

    3.原理解析

    缓存的组件以 [key,vnode] 的形式记录,keys记录缓存的组件key,依据inclued、exclude的值,并且当超过设置的max根据LUR算法进行清除。vue2.x和vue3.x相差不大。

    (1)keep-alive 在生命周期中做了什么?

    • created:初始化catch,keys。catch是一个缓存组件虚拟dom的数组,其中数组中对象的key是组件的key,value是组件的虚拟dom;keys是一个用来缓存组件的key的数组。
    • mounted:实时监听include、exclude属性的变化,并执行相应操作。
    • destroyed:删除掉所有缓存相关的数据。

    (2)源码

    地址:源码地址

    // 源码位置:src/core/components/keep-alive.jsexport default {
      name: 'keep-alive',  abstract: true,  PRops: {
        include: patternTyPEs,    exclude: patternTypes,    max: [String, Number]  }
    ,  created () {
        this.cache = Object.create(null)    this.keys = []  }
    ,  destroyed () {
        for (const key in this.cache) {
          pruneCacheEntry(this.cache, key, this.keys)    }
      }
    ,  mounted () {
           //查看是否有缓存没有缓存的话直接走缓存    this.cacheVNode()    // 这里借助 watch 监控 include  和 exclude   // 如果有变化的话,则按照最新的 include 和 exclude 更新 this.cache  // 将不满足 include、exclude 限制的 缓存vnode 从 this.cache 中移除    this.$watch('include', val =>
     {
              pruneCache(this, name =>
     matches(val, name))    }
        )    this.$watch('exclude', val =>
     {
              pruneCache(this, name =>
     !matches(val, name))    }
    )  }
    ,  updated() {
        this.cacheVNode()  }
    ,  methods:{
       cacheVNode() {
          const {
     cache, keys, vnodeToCache, keyToCache }
     = this      if (vnodeToCache) {
            const {
     tag, componentInstance, componentOptions }
     = vnodeToCache        cache[keyToCache] = {
              name: _getComponentName(componentOptions),          tag,          componentInstance        }
                keys.push(keyToCache)        // prune oldest entry        if (this.max &
        &
         keys.length >
     parseint(this.max)) {
              pruneCacheEntry(cache, keys[0], keys, this._vnode)        }
            this.vnodeToCache = null      }
        }
     }
    ,  render(){
        //下面详细介绍  }
    }
        

    (3)abstract:true

    设置为true时,表面该组件为抽象组件,抽象组件不会和子组件建立父子关系,组件实例会根据这个属性决定是否忽略该组件,所以并不会有节点渲染在页面中。

    (4)pruneCacheEntry函数

    destoryed周期中循环了所有缓存的组件,并用 pruneCacheEntry进行处理,pruneCacheEntry做了什么事?

    // src/core/components/keep-alive.jsfunction pruneCacheEntry (  cache: VNodeCache,  key: string,  keys: Arraystring>
    ,  current?: VNode) {
          const cached = cache[key]  if (cached &
        &
     (!current || cached.tag !== current.tag)) {
        cached.COMponentInstance.$destroy() // 执行组件的destory钩子函数  }
      cache[key] = null  // cache中对象的key设为null  remove(keys, key) // 删除keys对应的元素}
        

    destoryed周期中,删除缓存组件的所有数组,pruneCacheEntry主要做了这几件事:

    • 遍历缓存组件集合(cach),对所有缓存的组件执行$destroy方法
    • 清除cache中key的值
    • 清除keys中的key

    (5)render

    render中主要做了什么?

    • 获取keep-alive组件子节点中第一个组件的vnode、componentOptions、name
    • 如果name存在且不在include中或者存在在exclude中,则返回虚拟dom。此时该组件并没有使用缓存。
    • 接下来就是上面的else情况:使用keep-alive进行组件缓存,根据组件id,tag生成组件的key,如果cache集合中存在以key为属性名的vdom,,说明组件已经缓存过,则将缓存的 Vue 实例赋值给 vnode.componentInstance,从keys中删除key,再把key push导keys中,保证当前key在keys的最后面(这是LRU算法的关键)。如果不存在则继续走下面
    • 如果cach[key]不存在则为第一次加载组件,则把vdom赋值给cach[key],key push到key
    • 如果keys的长度大于max,则进行组件缓存清理,则把不经常使用的被缓存下来的在keys中排第一位的组件清除掉,清除也是调用的pruneCacheEntry方法
    render () {
        	// 获取 keep-alive 组件子节点中的第一个组件 vnode    const slot = this.$slots.default    const vnode = getFirstComponentChild(slot)    // 获取组件的配置选项对象    const componentOptions = vnode &
        &
     vnode.componentOptions    if (componentOptions) {
          // 获取组件的名称      const name = _getComponentName(componentOptions)      const {
     include, exclude }
         = this       // 如果当前的组件 name 不在 include 中或者组件的 name 在 exclude 中		  // 说明当前的组件是不被 keep-alive 所缓存的,此时直接 return vnode 即可      if (        // not included        (include &
        &
         (!name || !matches(include, name))) ||        // excluded        (exclude &
        &
         name &
        &
     matches(exclude, name))      ) {
            return vnode      }
         // 代码执行到这里,说明当前的组件受 keep-alive 组件的缓存      const {
     cache, keys }
     = this        // 定义 vnode 缓存用的 key      const key =        vnode.key == null          ? // same constructor may get registered as different local components            // so cid alone is not enough (#3269)            componentOptions.Ctor.cid +            (componentOptions.tag ? `::${
    componentOptions.tag}
    ` : '')          : vnode.key           // 如果 cache[key] 已经存在的话,则说明当前的组件 vnode 已经被缓存过了,此时需要将其恢复还原出来      if (cache[key]) {
          	// 将缓存的 Vue 实例赋值给 vnode.componentInstance        vnode.componentInstance = cache[key].componentInstance        // make current key freshest        	// 先从 keys 中移除 key,然后再 push key,这可以保证当前的 key 在 keys 数组中的最后面        remove(keys, key)        keys.push(key)      }
     else {
            // delay setting the cache until update        	// 如果 cache[key] 不存在的话,说明当前的子组件是第一次出现,此时需要将 vnode 缓存到 cache 中,将 key 存储到 keys 字符串数组中。这里是用一个中间变量接收,当数据变化时触发updated去调用cacheVNode方法。        this.vnodeToCache = vnode        this.keyToCache = key      }
          // @ts-expect-error can vnode.data can be undefined       // 将 vnode.data.keepAlive 属性设置为 true,这对 vnode 有一个标识的作用,标识这个		  // vnode 是 keep-alive 组件的 render 函数 return 出去的,这个标识在下面的运行代码中有用      vnode.data.keepAlive = true    }
            return vnode || (slot &
        &
     slot[0])  }
        

    三、LRU算法

    缓存的组件在进行清除的时候使用了LRU算法,具体是什么策略呢?当数据超过了限定空间的时候对数据清理,清理的原则是对很久没有使用到过的数据进行清除

    到此这篇关于vue2.x中keep-alive源码解析的文章就介绍到这了,更多相关vue2.x keep-alive源码内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!

    您可能感兴趣的文章:
    • Vue--keep-alive使用实例详解
    • vue使用keep-alive如何实现多页签并支持强制刷新
    • vue中keep-alive组件实现多级嵌套路由的缓存
    • vue使用keep-alive后清除缓存的方法
    • Vue中keep-alive 实现后退不刷新并保持滚动位置
    • vue keep-alive列表页缓存 详情页返回上一页不刷新,定位到之前位置
    • vue组件 keep-alive 和 transition 使用详解
    • vue使用keep-alive保持滚动条位置的实现方法
    • vue里如何主动销毁keep-alive缓存的组件

    声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!


    若转载请注明出处: vue2.x中keep-alive源码解析(实例代码)
    本文地址: https://pptw.com/jishu/609263.html
    Vue动态类的几种使用方法总结 Vue富文本插件(quill-editor)的使用及说明

    游客 回复需填写必要信息