在 VueJS 中使用 Keep-Alive 处理窗口调整事件,组件懒加载(在使用 keep-alive 缓存组件时,处理多个Vue页面的resize事件)

前言

我们在使用 VueJS 开发单页应用时,正确管理组件的生命周期事件对于保持应用性能和响应性至关重要。特别是当涉及到 <keep-alive> 包裹的组件时,合理处理如 resize 事件监听器显得尤为重要。由于这些组件会被缓存而不是频繁销毁重建,直接添加或移除事件监听可能会导致不必要的资源消耗甚至内存泄漏。

为了有效管理这类组件中的 resize 事件监听,建议利用 Vue 提供的 activateddeactivated 生命周期钩子。分别在子组件通过在 activated 钩子中设置监听器,并在 deactivated 中清理它,可以确保即使组件被缓存后,重新激活也能准确响应窗口大小变化,同时避免了潜在的性能问题。


一. 基本概念

1. 场景介绍

在 VueJS 中,组件的生命周期钩子允许我们在组件的特定阶段执行代码。常见的生命周期钩子包括 mounted、beforeDestroy 等。然而,当我们使用 keep-alive 包裹组件时,这些组件不会真正被销毁和重新创建,而是被缓存和重新激活。这就引入了两个新的生命周期钩子:activated 和 deactivated。

这里看下组件实例全部的生命周期函数,官方提供了(3个大类)共11个:

1. 创建阶段的四个: 
> beforeCreate:         实例创建之前。 
> created:                  实例创建之后。 
> beforeMount:          组件挂载之前。 
> mounted:                组件挂载之后。

2. 运行阶段的两个: 
> beforeUpdate:        数据改变,视图更新之前。
> updated:                 试图更新之后。 销毁阶段的两个: 
> beforeDestroy:       实例销毁之前。 
> destroyed:              实例销毁之后。


3. 其它三个:
> activated                                 被 keep-alive 缓存的组件激活时调用。
> deactivated                             被 keep-alive 缓存的组件停用时调用。
> errorCaptured 2.5.0+              新增当捕获一个来自子孙组件的错误时被调用

2. 具体场景

假设我们有多个组件需要在窗口大小调整时重新绘制。为了避免每个组件都监听 resize 事件,我们需要确保只有当前激活的组件响应该事件。这就需要我们在组件激活时添加事件监听器,在组件停用时移除监听器。以下是实现这一功能的详细步骤和代码示例。


二. 代码结构

1. 父组件结构

这里我们有一个父组件,它使用 <keep-alive> 包裹了多个子组件。

<template>
  <div class="anomalous_index">
    <transition name="" mode="" appear>
      <keep-alive>
        <anomal_1 v-if="twoContent === '异常1' && oneNavStatus === '异常事件'"/>
        <anomal_2 v-if="twoContent === '异常2' && oneNavStatus === '异常事件'"/>
        <anomal_3 v-if="twoContent === '异常3' && oneNavStatus === '异常事件'"/>
        <!-- 其他组件类似 -->
      </keep-alive>
    </transition>
  </div>
</template>

<script>
// 组件使用 3 步骤:1.引入 2.注册 3.使用
import anomal_1 from '@/views/test/index.vue';
import anomal_2 from '@/views/test/index.vue';
import anomal_3 from '@/views/test/index.vue';
export default {
  components: {      
    anomal_1 ,
    anomal_2 ,
    anomal_3 ,
  },  
  data() {
    return {
      twoContent: '',
      oneNavStatus: ''
    };
  }
};
</script>




||
<script>
export default {
  components: {
        // 组件懒加载
        anomal_1 :()=> import("@/views/test/index.vue"),
        anomal_2 :()=> import("@/views/test/index.vue"),
        anomal_3 :()=> import("@/views/test/index.vue")
  },  
  data() {
    return {
      twoContent: '',
      oneNavStatus: ''
    };
  }
};
</script>

2. 子组件结构

以 anomal_1 组件为例,我们在其中管理 resize 事件监听器。

<template>
  <div>
    <!-- 异常1的内容 -->
  </div>
</template>

<script>
export default {
  data() {
    return {
      // 存储 handleResize 事件处理程序的引用
      handleResize: null
    };
  },
  mounted() {
    // 在组件挂载时定义 handleResize 函数
    this.handleResize = this.$debounce(() => {
      console.log("anomal_1 resize event");
      this.initCanvas();
      this.getImage();
    }, 2000);
    // 添加 resize 事件监听器
    window.addEventListener("resize", this.handleResize);
  },
  activated() {
    // 在组件激活时重新添加 resize 事件监听器
    window.addEventListener("resize", this.handleResize);
  },
  deactivated() {
    // 在组件停用时移除 resize 事件监听器
    window.removeEventListener("resize", this.handleResize);
  },
  beforeDestroy() {
    // 在组件销毁前移除 resize 事件监听器
    window.removeEventListener("resize", this.handleResize);
  },
  methods: {
    initCanvas() {
      // 初始化画布的函数
    },
    getImage() {
      // 获取图片的函数
    }
  }
};
</script>
  • 这里不能使用 beforeDestroy 和 destroyed ,因为 beforeDestroy 钩子在 Vue  组件实例即将销毁之前触发,而 destroyed 实例销毁之后触发。
  • 当使用 keep-alive 包裹组件时,组件在切换时并不会真正销毁,而是会被缓存,因此beforeDestroy 钩子不会触发。这时可以使用 activated 和 deactivated 生命周期钩子来管理组件的事件监听器。


三. 应用总结


1. 事件处理程序的定义:

我们在 mounted 钩子中定义 handleResize 函数。this.$debounce 用于防抖处理,以减少频繁调用。

防抖应用,请看:

防抖函数的实际应用icon-default.png?t=O83Ahttps://blog.csdn.net/weixin_65793170/article/details/137824500?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522172242376316800182136521%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=172242376316800182136521&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-2-137824500-null-null.nonecase&utm_term=%E9%98%B2%E6%8A%96&spm=1018.2226.3001.4450


2. 事件监听器的管理:

  • 在 mounted 钩子中添加 resize 事件监听器。
  • 在 activated 钩子中重新添加 resize 事件监听器,确保组件被激活时可以响应事件。
  • 在 deactivated 钩子中移除 resize 事件监听器,避免组件停用时仍然响应事件。
  • 在 beforeDestroy 钩子中移除 resize 事件监听器,确保组件销毁时不会留下无效的监听器。

3. 文章小结

通过正确管理 VueJS 组件的生命周期钩子,特别是在使用 <keep-alive> 时,我们可以确保只有当前激活的组件响应 resize 事件。这种方法不仅提高了应用的性能,还减少了不必要的事件处理。

创作不易,感觉有用,就一键三连,感谢(●'◡'●)