requestAnimationFrame与计时器的区别详细教程

计时器一直是javascript动画的核心技术,而编写动画循环的关键是要知道延迟时间多长合适,一方面,循环间隔必须足够短,这样才能让不同的动画效果显得平滑流畅;另一方面,循环间隔还要足够长,这样才能确保浏览器有能力渲染产生的变化

大多数电脑显示器的刷新频率是60Hz,大概相当于重绘60次。大多数浏览器都会对重绘操作加以限制,不超过显示器的重绘频率,因为即使超过那个频率用户体验也不会有提升。因此,最平滑动画的最佳间隔是1000ms/60,约等于16.6ms

而setTimeout和setInterval的问题是,它们都不精确。它们的内在运行机制决定了时间间隔参数实际上只是指定了把动画代码添加到浏览器UI线程队列中以等待执行的时间。如果队列前面已经加入了其它任务,那动画代码就要等前面的任务完成后再执行

requestAnimationFrame采用系统时间间隔,保持最佳绘制效率,不会因为间隔时间过短,造成过度绘制,增加开销;也不会因为间隔时间太长,使用动画卡顿不流畅,让各种网页效果能够有一个统一的刷新机制,从而节省系统资源,提高系统性能,改善视觉效果

requestAnimationFram 介绍

 requestAnimationFram()和定时器 setTimeout()、setInterval() 是相关的,因为requestAnimationFrame 是H5新增的API,
 是为了解决定时器时间间隔不稳定的问题,

屏刷新频率是 60HZ ==> 也就是每秒60次. ==> 相当于1000毫秒60次 = 16.67ms一次。也就是说每16.67毫秒刷新一次
是浏览器显示的最大刷新频率。我们一般设置16或者17 接近这个频率。
setInterval(()=>{
// 是异步API,必须要等待同步任务后执行,具体说要等待微任务完成才会执行。
// 所以没有办法精准的定位这个时间 17,
// 所以h5 新增的 requestAnimationFrame 
},17)

requestAnimationFrame 的调用不是由JS来控制的,而且由系统的时间间隔来解决的。用法和setTimeout是类似的。
不一样的是当前的时间间隔是定死的,你不能控制而是有系统控制。
var timer =  requestAnimationFrame(()=>{
	console.log(timer )
})
cancelAnimationFrame(timer) // 清空

requestAnimationFram的兼容性

requestAnimationFrame 是H5新增的特性,遇到不兼容的情况如下解决
if(!window.requestAnimationFrame){
 	requestAnimationFrame = function(fn){
 		setTimeout(fn,17)
	}
}

requestAnimationFram的应用

  1. 创建LoadingBar.vue文件
<template>
	<div class="wraps">
		<div ref="bar" class="bar"></div>
	</div>
</template>
<script setup lang="ts">
import { ref } from "vue";
// 定义初始值
let speed = ref<number>(1);
let bar = ref<HTMLElement>();
let timer = ref<number>(0);
// 开始进度条
const startLoading = () => {
	let dom = bar.value as HTMLElement;
	window.requestAnimationFrame(function fn() {
		if (speed.value < 90) {
			speed.value += 1;
			dom.style.width = speed.value + "%";
			window.requestAnimationFrame(fn);
		} else {
			speed.value = 1;
			window.cancelAnimationFrame(timer.value);
		}
	});
};
// 结束进度条
const endLoading = () => {
	let dom = bar.value as HTMLElement;
	setTimeout(() => {
		window.requestAnimationFrame(() => {
			speed.value = 100;
			dom.style.width = speed.value + "%";
		});
	}, 5000);
};

// 把需要的方法暴露出去
defineExpose({
	startLoading,
	endLoading,
});
</script>
<style scoped lang="less">
.wraps {
	position: fixed;
	top: 0;
	width: 100%;
	height: 2px;
	.bar {
		height: inherit;
		width: 0;
		background-color: red;
	}
}
</style>

  1. 修改man.ts 文件
import { createApp, createVNode, render } from 'vue'
import App from './App.vue'
import router from './router'
import LoadingBar from './components/LoadingBar.vue'
// 转换成虚拟dom
const Vnode = createVNode(LoadingBar)
// 通过render函数挂载
render(Vnode, document.body)
// 白名单
const whileList = ['/']
// 导航守卫 前置守卫
router.beforeEach((to, from, next) => {
    Vnode.component?.exposed?.startLoading()
    if (whileList.includes(to.path) || localStorage.getItem('token')) {
        next()
    } else {
        next('/')
    }
})
router.afterEach((to, from) => {
    Vnode.component?.exposed?.endLoading()
})
createApp(App).use(router).mount('#app')

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值