requestAnimationFrame和cancelAnimationFrame
requestAnimationFrame
与setTimeout相比,requestAnimationFrame最大的优势是由系统来决定回调函数的执行时机。具体一点讲,如果屏幕刷新率是60Hz,那么回调函数就每16.7ms被执行一次,如果刷新率是75Hz,那么这个时间间隔就变成了1000/75=13.3ms,换句话说就是,requestAnimationFrame的步伐跟着系统的刷新步伐走。它能保证回调函数在屏幕每一次的刷新间隔中只被执行一次
cancelAnimationFrame
取消一个先前通过调用window.requestAnimationFrame()方法添加到计划中的动画帧请求。
这里需要注意下兼容性:
import {ref,onUnmounted} 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;
}
}
用于实现一个延迟函数。具体来说,它使用了Vue 3中的ref和onUnmounted函数,以及JavaScript中的requestAnimationFrame和cancelAnimationFrame函数。
函数接受一个maxCount参数,用于指定最大的帧数。在函数内部,创建了一个frameCount ref对象,并定义了一个updateFrameCount函数,用于递增frameCount的值,并在达到maxCount时停止递增。updateFrameCount函数使用requestAnimationFrame函数来实现帧数的递增,并在达到maxCount时停止递增。
最后,函数返回一个defer函数,用于检查当前帧数是否达到指定的值n。如果达到了,defer函数返回true,否则返回false。在组件中使用defer函数可以实现一些需要延迟执行的操作,例如我们这里可以用到的首屏加载速度优化。同时,因为这里是使用了onUnmounted函数,可以确保在组件销毁时停止帧数的递增,也能避免内存泄漏和性能问题。
使用方法:我可以将此方法放入初始启动的页面中,例如登录(如果页面速度快的话可以不用,我这里是因为登录页面特效较多)
import {useDefer} from '@/utils/useDefer';
const defer = useDefer()
<el-form ref="loginFormRef" v-if="defer(1)" :model="ruleForm" label-width="auto" :rules="rules">
<el-form-item label="用户名" prop="username">
<el-input v-model="ruleForm.username" clearable placeholder="请输入用户名" />
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input v-model="ruleForm.password" show-password placeholder="请输入密码" />
</el-form-item>
<el-row class="flex-button">
<el-button plain type="primary" :loading="isLoading" @click="submitForm(loginFormRef)">登录</el-button>
<el-button plain type="success" @click="resetForm(loginFormRef)">重置</el-button>
</el-row>
</el-form>
<div class="svg" v-if="defer(2)"></div>
<div class="svg" v-if="defer(3)"></div>
<div class="svg" v-if="defer(4)"></div>
<div class="svg" v-if="defer(5)"></div>
<div class="svg" v-if="defer(6)"></div>
...