Vue keep-alive

当使用动态组件时,当您切换 :is 指令的值时,Vue 会重新创建组件的新实例。尽管它在大多数情况下很有用,但有时我们想要保存隐藏元素的状态。

这时 Vue 的 keep-alive 组件就派上用场了,它可以是提高速度并提供更好的用户体验的好方法。

什么是 keep-alive

为了理解 <keep-alive>,您首先必须了解什么是动态组件。简而言之,它可以使用 v-bind:is 指令在不同组件之间切换。

最常见的示例是Tab 切换,其中根据打开的选项卡,内容切换到不同的组件。

通常,当您在动态组件之间切换时,Vue 会为您的组件创建一个全新的实例。

然而,Vue <keep-alive> 是一个围绕动态组件的包装器元素。当组件处于非活动状态时,它会存储对组件的缓存引用。

这意味着 Vue 不必每次切换组件时都创建一个新实例。相反,当您返回时,它只使用缓存的引用。

<keep-alive> 是 Vue 的抽象元素,这意味着它既不渲染 DOM 元素,也不显示为组件。

keep-alive 使用场景

在大多数情况下,动态组件的内置功能是完美的。在某些情况下,您可能想要缓存状态,例如:

  • 缓存表单上的用户输入,读取进度等。
  • 你的组件会调用很多 API,而你只想调用一次
  • 您的组件需要花一些时间来设置数据和计算属性,您希望在它们之间快速切换

基本使用

你可以在 Vue keep-alive 进行简单的测试,已经给出基本模板。

假设我们有一个父选项卡组件,它有两个子组件 AboutContact

<!-- About.vue -->
<template>
  <div>
    Hello Vue!
  </div>
</template>
<script>
export default {
  mounted() {
    console.log('已挂载 About')
  }
}
</script>

<!-- Contact.vue -->
<template>
  <div>
    <input type="text" placeholder="请输入内容..." />
    <input type="button" value="Send" />
  </div>
</template>
<script>
export default {
  mounted() {
    console.log('已挂载 Contact')
  }
}
</script>

父组件具有两个按钮,用于切换动态组件。

<template>
  <div>
    <button v-for='tab in tabs' :key='tab' @click='component = tab'>
      {{ tab }}
    </button>
    <component :is='component' />
  </div>
</template>
<script>
import About from "@/components/About.vue"
import Contact from "@/components/Contact.vue"
export default {
  components: { About, Contact },
  data () {
    return {
      tabs: ["About", "Contact"],
      component: "About"
    }
  }
}
</script>

现在,如果您运行您的应用程序,您应该会看到类似这样的内容。

image

在组件之间切换时,您应注意:

  • 每次切换选项卡时,来自 mount() 的消息都会打印在控制台中
image.png
  • 如果在 Contact 中填写输入,然后切换选项卡,在 Contact 选项卡输入的信息将不存在。
image.png

这两个都是因为没有使用 keep-alive,Vue 会创建组件的新实例,因此所有生命周期挂钩都会重新运行,并且您所做的任何输入都会丢失。

转到 Tabs.vue 组件,将动态组件包装在 <keep-alive> 组件中

<keep-alive>
  <component :is='component' />
</keep-alive>

现在上面出现的问题都不存在:

  • 来自 mount() 的消息应该由每个组件打印一次,并且只能打印一次

  • 如果您在 Contact 选项卡上输入信息,则在切换选项卡返回时,该输入仍应存在

虽然这是使用 keep-alive 组件的简单用例,但它是说明为什么要使用它们的一个很好的例子。

includeexcludemax

includeexclude 允许组件有条件地缓存。二者都可以用逗号分隔字符串、正则表达式或一个数组来表示,是 2.1.0 新增的属性

  • include:只有匹配的组件会被缓存。
  • exclude:任何匹配的组件都不会被缓存。
<!-- 逗号分隔字符串 -->
<keep-alive include="Contact">
 <component :is="component"></component>
</keep-alive>

<!-- 正则表达式 (使用 `v-bind`) -->
<keep-alive :include="/About|Contact/">
 <component :is="component"></component>
</keep-alive>

<!-- 数组 (使用 `v-bind`) -->
<keep-alive :include="['About', 'Contact']">
 <component :is="component"></component>
</keep-alive>

<!-- 与 include 用法一致,但目的是任何匹配的组件都不会被缓存。-->
<keep-alive exclude="Contact">
 <component :is="component"></component>
</keep-alive>

匹配首先检查组件自身的 name 选项,如果 name 选项不可用,则匹配它的局部注册名称(父组件 components 选项的键值)。匿名组件不能被匹配。

max 表示最多可以缓存多少组件实例。一旦这个数字达到了,在新实例被创建之前,已缓存组件中最久没有被访问的实例会被销毁掉。是 2.5.0 新增的属性。

<keep-alive :max="2">
  <component :is="view"></component>
</keep-alive>

keep-alive 生命周期钩子

为了帮助观察何时切换 <keep-alive> 的组件,我们有两个独特的钩子:

  • activated() 在被 keep-alive 缓存的组件激活时调用。

  • deactivated() 在被 keep-alive 缓存的组件停用时调用。

注意:这两个钩子在服务器端渲染期间不被调用。

使用前面的示例实现这些挂钩,在切换组件时将其输出到控制台。

// About.vue
mounted() {
  console.log('About 已挂载')
},
activated () {
  console.log('About 已激活')
},
deactivated () {
  console.log('About 已停用')
}

现在,如果我们运行我们的应用程序并在选项卡之间切换,我们将看到挂载的消息仅打印一次,而激活/停用的消息则重复打印。

注意:当动态组件首次显示时,它既已挂载又被激活。因此,确保您不会两次计算某些逻辑很重要。

结合 router,缓存部分页面

在 router 中设置路由的元信息 meta

export default new Router({
  routes: [
    {
      path: '/about',
      name: 'About',
      component: About,
      meta: {
        keepAlive: false // 不需要缓存
      }
    },
    {
      path: '/contact',
      name: 'Contact',
      component: Contact,
      meta: {
        keepAlive: true // 需要被缓存
      }
    }
  ]
})

使用 $route.metakeepAlive 属性进行

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

keep-alive 的利弊

当然,使用 <keep-alive> 而不只是默认的动态组件是有利有弊。

  • 优点:存储组件缓存,更快的组件
  • 缺点:容易过度使用,正常情况下往往足够好。

对于大多数情况,仅使用默认的动态组件而无需 <keep-alive> 是最佳解决方案。但是,如果您想轻松保存用户状态,则 <keep-alive> 组件是一种非常简单的方法。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,406评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,732评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,711评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,380评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,432评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,301评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,145评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,008评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,443评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,649评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,795评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,501评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,119评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,731评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,865评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,899评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,724评论 2 354

推荐阅读更多精彩内容

  • 当使用动态组件时,当您切换:is指令[https://vuejs.org/v2/guide/components....
    魂斗驴阅读 264评论 0 0
  • vue官网介绍(方便回忆使用) Props: include - 字符串或正则表达式。只有名称匹配的组件会被缓存。...
    新许88阅读 958评论 0 5
  • 一,VUE单页面应用文件实现返回上一页面时保留之前的数据 最近在做项目时,需要实现下面场景: 在页面查询列表,进入...
    工程狮子阅读 1,971评论 0 0
  • keep-alive keep-alive是Vue提供的一个抽象组件,用来对组件进行缓存,从而节省性能,由于是一个...
    羊烊羴阅读 232,690评论 7 103
  • keep-alive keep-alive是Vue提供的一个抽象组件,用来对组件进行缓存,从而节省性能,由于是一个...
    追寻1989阅读 226评论 0 0