[Vue面试] keep-alive 和 $set 的使用

keep-alive 的使用汇总于 半度℃温热圈圈同学

keep-alive

概念

keep-alive 是 Vue 的内置组件,当它包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 transition 相似,keep-alive 是一个抽象组件:它自身不会渲染成一个 DOM 元素,也不会出现在父组件链中。

作用

在组件切换过程中将状态保留在内存中,防止重复渲染DOM,减少加载时间及性能消耗,提升用户体验

原理

在 created 函数调用时将需要缓存的 VNode 节点(虚拟DOM,其实就是一个JS对象)保存在 this.cache 中/在 render(页面渲染) 时,如果 VNode 的 name 符合缓存条件(可以用 include 以及 exclude 控制),则会从 this.cache 中取出之前缓存的 VNode 实例进行渲染。

应用场景

用户在某个列表页面选择筛选条件过滤出一份数据列表,由列表页面进入数据详情页面,再返回该列表页面,我们希望:列表页面可以保留用户的筛选(或选中)状态。keep-alive就是用来解决这种场景。当然keep-alive不仅仅是能够保存页面/组件的状态这么简单,它还可以避免组件反复创建和渲染,有效提升系统性能。
总的来说,keep-alive用于保存组件的渲染状态。

用法

  • 在动态组件中的应用
<keep-alive :include="whiteList" :exclude="blackList" :max="amount">
  <component :is="currentComponent"></component>
</keep-alive>
  • 在 App.vue 中的应用
<keep-alive :include="whiteList" :exclude="blackList" :max="amount">
  <router-view></router-view>
</keep-alive>
  • 结合 vue-router,缓存部分页面
import Vue from 'vue'
import Router from 'vue-router'
const Home = resolve => require(['@/components/home/home'], resolve)
const Goods = resolve => require(['@/components/home/goods'], resolve)
const Ratings = resolve => require(['@/components/home/ratings'], resolve)
const Seller = resolve => require(['@/components/home/seller'], resolve)

Vue.use(Router)

export default new Router({
  mode: 'history',
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home,
      redirect: 'goods',
      children: [
        {
          path: 'goods',
          name: 'goods',
          component: Goods,
          meta: {
        	keepAlive: false // 不需要缓存
      	  }
        },
        {
          path: 'ratings',
          name: 'ratings',
          component: Ratings,
          meta: {
        	keepAlive: true  // 需要缓存
      	  }
        },
        {
          path: 'seller',
          name: 'seller',
          component: Seller,
          meta: {
        	keepAlive: true  // 需要缓存
      	  }
        }
      ]
    }
  ]
})

在 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>

<script>
export default {
  name: 'App'
}
</script>
  • include 定义缓存白名单,可以是一个以英文逗号分隔的字符串、一个正则表达式,或是包含这两种类型的一个数组,keep-alive 会缓存名称匹配的组件;
  • exclude 定义缓存黑名单,可以是一个以英文逗号分隔的字符串、一个正则表达式,或是包含这两种类型的一个数组,名称匹配的组件将不会被缓存;
  • max 数字,定义最多可以缓存多少组件实例,超出上限使用LRU的策略置换缓存数据。

生命周期函数

  • activated
    • 在 keep-alive 组件激活时调用,该钩子函数在服务器端渲染期间不被调用
  • deactivated
    • 在 keep-alive 组件停用时调用,该钩子在服务器端渲染期间不被调用

当组件在 <keep-alive> 内被切换,它的 activated 和 deactivated 这两个生命周期钩子函数将会被对应执行。

使用 keep-alive 会将数据保留在内存中,如果要在每次进入页面的时候获取最新的数据,需要在 activated 阶段获取数据,承担原来 created 钩子函数中获取数据的任务。

只有组件被 keep-alive 包裹时,这两个生命周期函数才会被调用,如果作为正常组件使用,是不会被调用的


vm.$set

这里为什么不是this而是vm?

他们都是指的vue实例

var vm = new Vue({
  data: {
    a: 1
  }
})
vm.$set(vm.userProfile, 'age', 27)

作用

向响应式对象中添加一个 property,并确保这个新 property 同样是响应式的,且触发视图更新。它必须用于向响应式对象上添加新 property,因为 Vue 无法探测普通的新增 property (比如 this.myObject.newProperty = ‘hi’)

应用场景

当我们更改了数据之后,视图没有跟随数据的改动发生变化,即双向数据绑定失效;

根据官方文档,双向数据绑定失效总共有三种情况:

  1. 当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue
  2. 当你修改数组的长度时,例如:vm.items.length = newLength
  3. 对象中的属性增加或删除时

用法

  1. 使用 this.$set(obj, key, value)/vue.set(obj, key, value)
    数组写法:this.$set(原数组, 索引值, 需要赋的值)
    对象写法:
<script>
export default {
 data() {
   return {
     student: {
       name: '张三',
     }
   }
 },
 methods: {
   setMessage() {
     this.$set(this.student, 'age', 15)
     console.log(this.student)
   }
 }
}
</script>
  1. 通过 Object.assign(target, sources) 方法
<script>
export default {
  data() {
    return {
      student: {
        name: '张三',
      }
    }
  },
  methods: {
    setMessage() {
      this.student.age = 15
      this.student = Object.assign({}, this.student)
      console.log(this.student)
    }
  }
}
</script>

这两篇介绍的可能更加详细:文章1文章2

### Vue 中 `keep-alive` 组件的缓存回收机制 #### 缓存回收策略 在 Vue 应用中,`keep-alive` 是一种用于缓存组件实例的技术。当包裹动态组件时,会缓存不活动的组件实例而不是销毁它们[^2]。 对于缓存回收的时间控制以及如何管理这些缓存的数据,Vue 并未提供直接通过配置项来设定具体时间的方式。相反,开发者可以通过监听特定生命周期钩子函数来进行手动干预: - **activated**: 当组件被激活(即重新进入视图)时触发。 - **deactivated**: 当组件失活(离开当前显示区域)时调用,在服务端渲染期间不会执行此操作[^1]。 这意味着如果希望实现基于时间或其他条件下的自动清除功能,则需自行编写逻辑处理程序。例如可以利用 JavaScript 的定时器 API 来跟踪每个已缓存页面的存在期限,并在其达到预设时限后移除对应的条目。 #### 实现自定义缓存清理方案 为了更好地管理释放不再需要的资源,可以在应用层面增加一层抽象层来封装这一过程。下面是一个简单的例子展示如何创建一个具有过期机制的服务类: ```javascript class CacheService { constructor(timeout) { this.cache = new Map(); this.timeout = timeout; } add(key, value) { const entry = {value, timestamp: Date.now()}; this.cache.set(key, entry); setTimeout(() => { this.remove(key); }, this.timeout); } get(key) { let item = this.cache.get(key); if (item && (Date.now() - item.timestamp >= this.timeout)) { this.remove(key); return null; } return item ? item.value : null; } remove(key) { this.cache.delete(key); } } ``` 然后可以根据路由名称或者其他唯一标识符作为键存储到上述服务对象里去;每当访问某个受保护路径之前先查询一次是否有匹配记录存在并判断其有效性即可完成基本的功能需求。 最后一步是在适当的地方集成这个工具——比如全局导航守卫当中或者单独为每一个符合条件的目标组件添加相应的事件处理器。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值