当使用动态组件时,当您切换 :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>

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




keepalived vip 跨网段无法通信_前端框架


image


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

  • 每次切换选项卡时,来自 mount() 的消息都会打印在控制台中


keepalived vip 跨网段无法通信_前端框架_02

image.png

  • 如果在 Contact 中填写输入,然后切换选项卡,在 Contact 选项卡输入的信息将不存在。


keepalived vip 跨网段无法通信_vue.js_03

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> 组件是一种非常简单的方法。