keep-alive组件的作用与原理

这篇具有很好参考价值的文章主要介绍了keep-alive组件的作用与原理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

原文合集地址如下,有需要的朋友可以关注

本文地址

什么是keep-alive

“keep-alive” 是 Vue.js 中的一个特殊组件,用于缓存组件的状态,以提高应用性能。在 Vue.js 中,组件通常是动态创建和销毁的,当切换到另一个页面或组件时,之前的组件会被销毁,再次进入时会重新创建和初始化。这样可能导致组件的状态丢失,需要重新初始化,增加了资源的消耗。

组件解决了这个问题,它可以将组件缓存起来,而不是销毁,使得组件在再次进入时保持之前的状态,以及避免重复的创建和初始化过程。这样可以大幅度提高组件的加载速度和性能。

keep-alive的作用

<keep-alive> 的作用是在 Vue.js 应用中缓存组件的状态,以提高应用性能和用户体验。它可以将组件暂时保存在内存中,而不是每次都重新创建和初始化组件。

主要的作用有以下几点:

  1. 组件状态保持:通过使用 <keep-alive>,在组件被切换时,其状态会被保留。这意味着组件内部的数据、状态以及一些计算结果都会被缓存,不会因为组件的销毁而丢失。当再次进入该组件时,它会恢复到之前的状态,而不需要重新初始化。这对于用户在不同页面或组件间切换时提供了更流畅的体验。

  2. 减少资源消耗:如果没有使用 <keep-alive>,每次切换到一个组件时,都需要重新创建和初始化组件。对于复杂的组件,这可能会导致不必要的资源消耗,例如重新加载数据、执行复杂的计算等。而使用 <keep-alive>,组件被缓存起来,下次再次进入时直接从缓存中恢复,避免了重复的初始化过程,大大减少了资源消耗。

  3. 优化性能:由于避免了重复的创建和初始化过程,使用 <keep-alive> 可以显著提高组件的加载速度,加快页面响应时间,从而提供更好的用户体验。

需要注意的是,<keep-alive> 并不是适用于所有组件的,特别是对于一些动态变化的组件,如果希望每次进入时都重新初始化,或者希望释放组件占用的资源,就不应该使用 <keep-alive>

要使用 <keep-alive>,只需将需要缓存的组件包裹在 <keep-alive> 标签中即可,Vue.js 会自动管理缓存和组件的生命周期。这是一个简单但强大的功能,可在合适的场景下大幅度提升应用性能。

原理

<keep-alive> 的原理主要涉及两个方面:组件缓存和生命周期的管理。

  1. 组件缓存

    • 当一个组件被包裹在 <keep-alive> 标签中时,Vue.js 会将该组件的实例缓存起来,而不是销毁它。
    • 组件的缓存是通过一个名为 cache 的对象来管理的,该对象会保存被缓存的组件实例。
    • 当切换到一个被缓存的组件时,Vue.js 首先检查 cache 对象中是否已经有该组件的缓存实例。如果有,就直接从缓存中取出该实例;如果没有,就创建一个新的组件实例并将其缓存起来。
  2. 生命周期的管理

    • 在切换到一个被缓存的组件时,组件的生命周期钩子函数并不会被触发,而是会触发 <keep-alive> 自己的生命周期钩子函数。
    • <keep-alive> 组件有两个主要的生命周期钩子函数:createddestroyed
    • 在组件第一次被缓存时,created 钩子函数会被触发,表示 <keep-alive> 组件已经创建,此时会创建被缓存组件的实例并将其缓存起来。
    • 在切换到其他组件时,destroyed 钩子函数会被触发,表示 <keep-alive> 组件将被销毁,此时会销毁所有缓存的组件实例。

需要注意的是,被包裹在 <keep-alive> 标签中的组件,必须具有唯一的标识,否则会导致缓存冲突。默认情况下,Vue.js 使用组件的名称作为缓存的标识,但也可以通过 key 属性来指定唯一的标识。

使用 <keep-alive> 时,要注意以下几点:

  • 不是所有组件都适合使用 <keep-alive>,对于一些动态变化的组件,或者需要每次进入时重新初始化的组件,应该避免使用 <keep-alive>
  • 缓存的组件仍然会触发 activateddeactivated 生命周期钩子函数,可以在这两个钩子函数中处理一些特定的逻辑。
  • 如果被缓存的组件包含了一些依赖于外部状态(如路由参数、Vuex 状态等)的逻辑,需要特别注意在重新进入组件时是否需要重新更新这些状态。

总的来说,<keep-alive> 提供了一种简单且强大的机制来优化 Vue.js 应用的性能,特别是在频繁切换组件的场景下。

使用

当您使用 <keep-alive> 组件时,通常需要将需要缓存的组件包裹在 <keep-alive> 标签中,并为每个被缓存的组件设置一个唯一的 key 属性,以确保缓存的正确性。下面是一个使用 <keep-alive> 组件的示例:

假设我们有两个组件,一个是用于显示用户信息的组件 <UserProfile>,另一个是用于显示用户订单信息的组件 <UserOrders>。我们希望在用户切换到 <UserProfile> 组件时,保持该组件的状态,并且在用户切换到 <UserOrders> 组件后再切换回来时,不重新初始化 <UserProfile> 组件。

<template>
  <div>
    <keep-alive>
      <!-- 使用 key 属性确保组件的正确缓存 -->
      <component :is="currentComponent" :key="currentComponent" />
    </keep-alive>

    <button @click="showUserProfile">Show User Profile</button>
    <button @click="showUserOrders">Show User Orders</button>
  </div>
</template>

<script>
import UserProfile from './UserProfile.vue';
import UserOrders from './UserOrders.vue';

export default {
  components: {
    UserProfile,
    UserOrders,
  },
  data() {
    return {
      currentComponent: 'UserProfile', // 初始显示用户信息组件
    };
  },
  methods: {
    showUserProfile() {
      this.currentComponent = 'UserProfile';
    },
    showUserOrders() {
      this.currentComponent = 'UserOrders';
    },
  },
};
</script>

在上面的示例中,使用了动态组件 <component :is="currentComponent"> 来动态地切换显示 <UserProfile><UserOrders> 组件。同时,将 <keep-alive> 标签包裹在动态组件外部,这样 <keep-alive> 会缓存当前被显示的组件。

在切换组件时,使用 key 属性来确保缓存的正确性。当切换到不同的组件时,key 的值会变化,这会触发 <keep-alive> 的重新缓存行为。

注意,key 属性应该是唯一的,以确保每个组件都能被正确地缓存。在实际应用中,可能需要根据组件的具体情况设置不同的 key 值。

理解源码

<keep-alive> 组件的源码相对比较复杂,涉及到 Vue.js 的虚拟 DOM、组件实例管理、生命周期管理等方面。下面简要介绍 <keep-alive> 的关键源码部分,以便了解其基本原理。

在 Vue.js 的源码中,<keep-alive> 组件是由一个特殊的内置组件 KeepAlive 实现的。它的主要作用是处理组件的缓存和管理缓存组件的生命周期。

  1. 组件的缓存实现:

    • KeepAlive 组件内部维护了一个名为 cache 的对象,用于存储缓存的组件实例。
    • 在切换到一个被缓存的组件时,KeepAlive 组件首先会检查 cache 对象,是否已经有该组件的缓存实例。
    • 如果缓存中有该组件实例,KeepAlive 直接返回缓存的组件实例;如果没有,KeepAlive 会创建一个新的组件实例,并将其缓存起来。
  2. 组件生命周期的管理:

    • KeepAlive 组件有两个重要的生命周期钩子函数:createddestroyed
    • created 钩子函数中,KeepAlive 会监听父组件的 includeexclude 属性的变化,以决定是否缓存某个组件。
    • 在切换到被缓存组件时,KeepAlive 会触发 activated 生命周期钩子函数,并从 cache 中取出对应的缓存组件实例。如果没有缓存实例,会触发被缓存组件的 created 生命周期。
    • 在切换到其他组件时,KeepAlive 会触发 deactivated 生命周期钩子函数,并将当前缓存的组件实例暂时从 cache 中移除。如果需要缓存,则缓存的组件实例并不会被销毁。
  3. 组件销毁时的处理:

    • destroyed 钩子函数中,KeepAlive 会销毁所有缓存的组件实例,并清空 cache 对象。

如果想深入了解 <keep-alive> 的源码实现,可以查阅 Vue.js 的 GitHub 仓库并浏览相关代码 keep-alive源码。
这个是从github拿的源码,有兴趣可以研究一下。文章来源地址https://www.toymoban.com/news/detail-657083.html

import { isRegExp, isArray, remove } from 'shared/util'
import { getFirstComponentChild } from 'core/vdom/helpers/index'
import type VNode from 'core/vdom/vnode'
import type { VNodeComponentOptions } from 'types/vnode'
import type { Component } from 'types/component'
import { getComponentName } from '../vdom/create-component'

type CacheEntry = {
  name?: string
  tag?: string
  componentInstance?: Component
}

type CacheEntryMap = Record<string, CacheEntry | null>

function _getComponentName(opts?: VNodeComponentOptions): string | null {
  return opts && (getComponentName(opts.Ctor.options as any) || opts.tag)
}

function matches(
  pattern: string | RegExp | Array<string>,
  name: string
): boolean {
  if (isArray(pattern)) {
    return pattern.indexOf(name) > -1
  } else if (typeof pattern === 'string') {
    return pattern.split(',').indexOf(name) > -1
  } else if (isRegExp(pattern)) {
    return pattern.test(name)
  }
  /* istanbul ignore next */
  return false
}

function pruneCache(
  keepAliveInstance: { cache: CacheEntryMap; keys: string[]; _vnode: VNode },
  filter: Function
) {
  const { cache, keys, _vnode } = keepAliveInstance
  for (const key in cache) {
    const entry = cache[key]
    if (entry) {
      const name = entry.name
      if (name && !filter(name)) {
        pruneCacheEntry(cache, key, keys, _vnode)
      }
    }
  }
}

function pruneCacheEntry(
  cache: CacheEntryMap,
  key: string,
  keys: Array<string>,
  current?: VNode
) {
  const entry = cache[key]
  if (entry && (!current || entry.tag !== current.tag)) {
    // @ts-expect-error can be undefined
    entry.componentInstance.$destroy()
  }
  cache[key] = null
  remove(keys, key)
}

const patternTypes: Array<Function> = [String, RegExp, Array]

// TODO defineComponent
export default {
  name: 'keep-alive',
  abstract: true,

  props: {
    include: patternTypes,
    exclude: patternTypes,
    max: [String, Number]
  },

  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
      }
    }
  },

  created() {
    this.cache = Object.create(null)
    this.keys = []
  },

  destroyed() {
    for (const key in this.cache) {
      pruneCacheEntry(this.cache, key, this.keys)
    }
  },

  mounted() {
    this.cacheVNode()
    this.$watch('include', val => {
      pruneCache(this, name => matches(val, name))
    })
    this.$watch('exclude', val => {
      pruneCache(this, name => !matches(val, name))
    })
  },

  updated() {
    this.cacheVNode()
  },

  render() {
    const slot = this.$slots.default
    const vnode = getFirstComponentChild(slot)
    const componentOptions = vnode && vnode.componentOptions
    if (componentOptions) {
      // check pattern
      const name = _getComponentName(componentOptions)
      const { include, exclude } = this
      if (
        // not included
        (include && (!name || !matches(include, name))) ||
        // excluded
        (exclude && name && matches(exclude, name))
      ) {
        return vnode
      }

      const { cache, keys } = this
      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
      if (cache[key]) {
        vnode.componentInstance = cache[key].componentInstance
        // make current key freshest
        remove(keys, key)
        keys.push(key)
      } else {
        // delay setting the cache until update
        this.vnodeToCache = vnode
        this.keyToCache = key
      }

      // @ts-expect-error can vnode.data can be undefined
      vnode.data.keepAlive = true
    }
    return vnode || (slot && slot[0])
  }
}

到了这里,关于keep-alive组件的作用与原理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Vue3】keep-alive 缓存组件

    当在 Vue.js 中使用 keep-alive 组件时,它将会缓存动态组件,而不是每次渲染都销毁和重新创建它们。这对于需要在组件间快速切换并且保持组件状态的情况非常有用。 keep-alive 只能包含(或者说只能渲染)一个子组件,如果需要包含多个子组件,需要用 v-if 选择某个确定的组

    2024年02月13日
    浏览(42)
  • Vue中的keep-alive缓存组件的理解

    keep-alive 是一个抽象组件,用于将其内部的组件保留在内存中,而不会重新渲染。这意味着当组件在keep-alive 内部切换时,其状态将被 保留 ,而不是被销毁和重新创建。          keep-alive用来缓存不经常变化的组件,以提高性能,当我们在不同路由之间进行切换或者是动

    2024年01月18日
    浏览(39)
  • Vue keep-alive的使用和原理解析

    在当今Web开发领域中,构建交互性强、可复用且易于维护的用户界面是至关重要的。而Vue.js作为一款现代化且流行的JavaScript框架,正是为了满足这些需求而诞生。它采用了MVVM架构模式,并通过数据驱动和组件化的方式,使我们能够更轻松地构建出优雅而高效的Web应用程序。

    2024年01月16日
    浏览(46)
  • Vue.js 进阶技巧:keep-alive 缓存组件解析

    🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_ CSDN 博客专家、23年度博客之星前端领域TOP1 🕠 牛客 高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课 签约作者、上架课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你

    2024年03月11日
    浏览(86)
  • 缓存滚动位置:解决keep-alive组件缓存滚动位置失败问题

    怎样在vue中缓存组件?大家都知道,使用keep-alive组件即可,但是使用keep-alive缓存页面后,发现虽然页面缓存成功了,但是列表的滚动条又自动回到了最上方。 是的, keep-alive组件是不会缓存滚动位置的 。 怎样缓存滚动位置呢?这是我们这一章讲的问题。 核心思想是在路由

    2024年02月16日
    浏览(44)
  • Vue路由组件的缓存keep-alive和include属性

    功能:浏览器页面在进行切换时,原有的路由组件会被销毁。通过缓存可以保存被切换的路由组件。 例子:在页面上填好的信息当进行页面切换再转回原来的页面时,原本信息被清空了需要重新填写 功能:切换路由时,保留被切换路由组件。 格式: keep-alive router-view/ keep-

    2024年02月06日
    浏览(40)
  • vue3,动态引入组件,同时动态设置组件的name,用于keep-alive缓存

    如果有两个页面逻辑大都相同,咱们想到的第一个肯定是写一个组件,然后两个路由都指向这个组件。 那如果现在多添加一个需求:两个页面在切换路由时都需要缓存数据,并且两个页面的缓存数据要求独立。 这个需求很简单:在router-view外层包裹一个keep-alive组件,指定缓

    2024年02月14日
    浏览(46)
  • Vue使用keep-alive设置哪些组件可以被缓存,哪些不被缓存

    需求:当一个项目中,不是所有的组件页面都需要缓存起来,因为有些页面是不需要的    $route.meta.keepAlive 判断当前组件是否有keepAlive属性 在路由js文件中在配置路由规则的时候配置  

    2024年02月16日
    浏览(41)
  • vue3,vite开发, 动态引入组件,同时动态设置组件的name,用于keep-alive缓存

    如果有两个页面逻辑大都相同,咱们想到的第一个肯定是写一个组件,然后两个路由都指向这个组件。 那如果现在多添加一个需求:两个页面在切换路由时都需要缓存数据,并且两个页面的缓存数据要求独立。 这个需求很简单:在router-view外层包裹一个keep-alive组件,指定缓

    2024年02月07日
    浏览(45)
  • keep-alive 是 Vue 的一个内置组件,用于缓存其他组件的实例,以避免重复渲染和销毁,它可以在需要频繁切换的组件之间提供性能优化

    目录 keep-alive  使用 keep-alive 的示例代码: 手动清除组件缓存的示例代码: keep-alive 组件有以下几个优点: keep-alive 的原理: 使用 keep-alive 组件,你可以包裹需要缓存的组件,然后这些组件在切换时将会被缓存起来,而不是每次都重新创建。 使用 keep-alive 的示例代码: 我们

    2024年02月08日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包