利用 Vue 组合式 API 与 requestAnimationFrame 优化大量元素渲染

在 Vue 项目开发中,当面临需要渲染大量元素的场景时,如何高效地处理渲染过程以避免性能瓶颈是一个关键问题。本文将深入探讨一种基于 Vue 3 的 <script setup> 语法糖和 requestAnimationFrame 的解决方案,通过自定义 useDefer 组合式函数来逐步渲染大量元素,提升页面性能与用户体验。

一、问题引入

在前端开发中,直接渲染大量元素可能会导致页面卡顿甚至无响应。例如,当我们需要在页面上展示 10000 个数据项时,如果一次性将所有元素都渲染到页面上,浏览器需要处理大量的 DOM 操作,这对于性能来说是一个巨大的挑战。用户可能会看到长时间的白屏或者页面滚动不流畅等问题,严重影响了用户体验。

二、useDefer 组合式函数解析

1. 函数定义与基本变量

javascript 复制代码
import {onUnmounted, ref} from "vue";

export function useDefer(maxCount = 100) {
    const frameCount = ref(0);
    let rafId;

这里首先从 Vue 中引入了 onUnmountedrefref 用于创建一个响应式数据,frameCount 就是一个响应式的变量,用于记录当前已经经过的动画帧数。rafId 则用于存储 requestAnimationFrame 返回的 ID,以便后续在组件卸载时能够取消动画帧的请求。

2. updateFrameCount 函数 - 动画帧更新逻辑

javascript 复制代码
function updateFrameCount() {
    rafId = requestAnimationFrame(() => {
        frameCount.value++;
        if (frameCount.value >= maxCount) {
            return;
        }
        updateFrameCount();
    });
}

updateFrameCount 函数是整个逻辑的核心部分。它使用 requestAnimationFrame 来创建一个动画帧的循环。在每一帧中,首先将 frameCount 的值加 1,表示已经经过了一个新的动画帧。然后检查 frameCount 是否已经达到了预设的 maxCount。如果没有达到,就继续递归调用 updateFrameCount,这样就形成了一个持续运行的动画帧更新循环,直到达到 maxCount 为止。

3. 组件卸载时的清理工作

javascript 复制代码
onUnmounted(()=>{
    cancelAnimationFrame(rafId);
})

当组件卸载时,使用 onUnmounted 钩子函数来取消之前通过 requestAnimationFrame 创建的动画帧请求。这是非常重要的一步,避免了在组件已经不需要更新时仍然占用浏览器资源,防止内存泄漏等问题。

4. defer 函数 - 元素渲染控制

javascript 复制代码
return function defer(n) {
    return frameCount.value >= n;
}

最后返回的 defer 函数接受一个参数 n,它会根据当前的 frameCount 值与传入的 n 进行比较。如果 frameCount 的值大于等于 n,则表示当前元素可以进行渲染,返回 true;否则返回 false。这样就可以在模板中根据元素的索引来控制元素的渲染时机,实现逐步渲染的效果。

三、组件中的使用

在 Vue 组件中,使用 useDefer 组合式函数非常简单:

html 复制代码
<script setup>
import {useDefer} from '@/hooks/useDefer'
const defer = useDefer()
</script>

<template>
  <div v-for="(item,index) in 10000">
    <div class="box" v-if="defer(index)">
      {{ item }}
    </div>
  </div>
</template>

通过引入 useDefer 函数并获取 defer 实例,在模板的 v-for 循环中,使用 v-if 指令结合 defer 函数来根据元素的索引控制每个 div 元素的渲染时机。这样,不是一次性渲染所有 10000 个元素,而是按照 requestAnimationFrame 设定的帧率逐步渲染,减轻了浏览器的负担,提高了页面的响应速度和流畅度。

四、总结与优化思考

通过自定义的 useDefer 组合式函数,我们有效地解决了大量元素渲染时可能出现的性能问题。这种方式利用了 requestAnimationFrame 与 Vue 的组合式 API 的优势,实现了元素的逐步渲染。然而,在实际应用中,还可以进一步优化。例如,可以根据页面的可见区域动态调整 maxCount 的值,只渲染当前可见区域附近的元素,对于不可见区域的元素延迟渲染甚至不渲染,进一步提高性能。同时,也可以考虑添加更多的参数来灵活控制渲染策略,以适应不同的业务场景和性能需求。希望本文能够为 Vue 开发者在处理大量元素渲染问题时提供一种有效的思路和解决方案,让我们能够构建出更加高效、流畅的 Vue 应用程序。

五、整体JS代码

javascript 复制代码
import {onUnmounted, ref} from "vue";

export function useDefer(maxCount = 100) {
    const frameCount = ref(0);
    let rafId;
    function updateFrameCount() {
        rafId = requestAnimationFrame(() => {
            frameCount.value++;
            if (frameCount.value >= maxCount) {
                return;
            }
            updateFrameCount();
        });
    }

    updateFrameCount();
    onUnmounted(()=>{
        cancelAnimationFrame(rafId);
    })
    return function defer(n) {
        return frameCount.value >= n;
    }
}
相关推荐
m0_47119963几秒前
【自动化】前端开发,如何将 Jenkins 与 Gitee 结合实现自动化的持续集成(构建)和持续部署(发布)
前端·gitee·自动化·jenkins
w***95491 分钟前
spring-boot-starter和spring-boot-starter-web的关联
前端
Moment5 分钟前
富文本编辑器技术选型,到底是 Prosemirror 还是 Tiptap 好 ❓❓❓
前端·javascript·面试
xkxnq10 分钟前
第二阶段:Vue 组件化开发(第 18天)
前端·javascript·vue.js
晓得迷路了12 分钟前
栗子前端技术周刊第 112 期 - Rspack 1.7、2025 JS 新星榜单、HTML 状态调查...
前端·javascript·html
怕浪猫14 分钟前
React从入门到出门 第五章 React Router 配置与原理初探
前端·javascript·react.js
jinmo_C++14 分钟前
从零开始学前端 · HTML 基础篇(一):认识 HTML 与页面结构
前端·html·状态模式
鹏多多21 分钟前
前端2025年终总结:借着AI做大做强再创辉煌
前端·javascript
哈__24 分钟前
React Native 鸿蒙跨平台开发:Vibration 实现鸿蒙端设备的震动反馈
javascript·react native·react.js
WebGISer_白茶乌龙桃26 分钟前
Cesium实现“悬浮岛”式,三维立体的行政区划
javascript·vue.js·3d·web3·html5·webgl