利用 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;
    }
}
相关推荐
passerby606140 分钟前
完成前端时间处理的另一块版图
前端·github·web components
掘了1 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅1 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅1 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅2 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment2 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅2 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊2 小时前
jwt介绍
前端
爱敲代码的小鱼2 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax
吹牛不交税2 小时前
admin.net-v2 框架使用笔记-netcore8.0/10.0版
vue.js·.netcore