vue3 如何通过defer来优化减少白屏时间

发布时间 2023-06-07 18:00:11作者: 10后程序员劝退师

如果首屏加载的内容组件比较厚重或者数量大,那么第一次加载也会停顿很久。

可以通过控制台的Performence来观察render和loading的大致时间

优化的思路: 想让首屏页面的组件或者比较需要提前让用户看到的内容模块 优先放在第一帧来加载

加载时机:如果当前帧数时间大于 该模块的设定指定加载帧数时间,就让模块去加载

案例:目前通过大组件的案例来实践

<template>
    <div class="container">
        <div v-for="n in 100" :key="n">            //这里通过重复的大组件来实现效果 
            <heavyComp v-if="defer(n)"></heavyComp>  //当 defer 返回 true 代表组件加载的时机
        </div>
    </div>
</template>

<script setup>
import heavyComp from '@/components/heavyComp.vue'
import {useDefer} from '@/utils/useDefer'
const defer = useDefer(100)
</script>

<style lang="scss" scoped>
.container{
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-gap: 1em;
}

</style>

创建一个useDefer 的hook函数

import { onUnmounted, ref, getCurrentInstance } from "vue"

export function useDefer(maxCount = 100){
    const frameCount = ref(0) //定义一个计数器变量,用于控制 defer 动画的次数,当为 0
    const instance = getCurrentInstance() //获取当前实例对象,可以是 vm 对象或自定义实例。这个对象包含了一些方法,用于控制动画。 (请参见该实例的方法) 创建 defer 动画时,将 frameCount.value 加 1 并将其写入到动画定时器中,每当该变量的值大于等于 1 时,将重新开始定时器,以便在定时器中计数。
    let rafId;
    function updateFrameCount() {
        rafId = requestAnimationFrame(() => {      //requestAnimationFrame来设置当前已经渲染到哪一帧了
            frameCount.value++
            if(frameCount.value >= maxCount){
                cancelAnimationFrame(rafId)
                return;
            }
            updateFrameCount()
        })
    }
    updateFrameCount();

    onUnmounted(() => {
        cancelAnimationFrame(rafId)
    }, instance)

    return function defer(n){
        return frameCount.value >= n
    }
}