requestAnimationFrame用法及说明

requestAnimationFrame它是请求动画帧,以浏览器的显示帧率来作为其动画动作的频率。比如浏览器每16.7ms刷新一次,动画回调也会每16.7ms调用一次

用法:requestAnimationFrame(callback);

该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行,回调函数执行次数通常与 浏览器屏幕刷新次数 相匹配。

终止执行

window.cancelAnimationFrame() 可以取消回调函数。 只需要把 requestAnimationFrame 的返回值作为参数传递给 cancelAnimationFrame 就可以了

requestAnimationFrame 与 setTimeout 、 setInterval用来做动画的优缺点

setTimeout 和 setInterval 的问题是,它们不够精确。它们的内在运行机制决定了 时间间隔参数 实际上只是指定了把动画代码添加到 浏览器UI线程队列 中以等待执行的时间。如果队列前面已经加入了其它任务,那动画代码就要等前面的 任务完成后 再执行,并且如果时间间隔过短(小于16.7ms)会造成丢帧,所以就会导致动画可能不会按照预设的去执行,降低用户体验。

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

        <div id="test"
			style="width: 0px; height: 12px; line-height: 12px; margin-bottom: 5px; background: rgb(185, 236, 243);">
		</div>
		当前进度:<span id="progress">0%</span>
		<button id="btn">开启</button>
            const btn = document.getElementById('btn');
			const test = document.getElementById('test');

			//使用 requestAnimationFrame 实现
			btn.onclick = function() {
				var timer = requestAnimationFrame(function fn() {
					if (parseInt(test.style.width) < 300) {
						test.style.width = parseInt(test.style.width) + 3 + 'px';
						progress.innerHTML = parseInt(test.style.width) / 3 + '%';
						timer = requestAnimationFrame(fn);
					} else {
						cancelAnimationFrame(timer);
					}
				});
			}

			//使用 setInterval 实现
			btn.onclick = function() {
				var timer = setInterval(function() {
					if (parseInt(test.style.width) < 300) {
						test.style.width = parseInt(test.style.width) + 3 + 'px';
						progress.innerHTML = parseInt(test.style.width) / 3 + '%';
					} else {
						clearInterval(timer);
					}
				}, 17);
			}

			//使用 setTimeout 实现
			btn.onclick = function() {
				var timer = setTimeout(function fn() {
					if (parseInt(test.style.width) < 300) {
						test.style.width = parseInt(test.style.width) + 3 + 'px';
						progress.innerHTML = parseInt(test.style.width) / 3 + '%';
						timer = setTimeout(fn, 17);
					} else {
						clearTimeout(timer);
					}
				}, 17);
			}

浏览器渲染有个渲染时机(Rendering opportunity)的问题,也就是浏览器会根据当前的浏览上下文判断是否进行渲染,它会尽量高效,只有必要的时候才进行渲染,如果没有界面的改变,就不会渲染。按照规范里说的一样,因为考虑到硬件的刷新频率限制、页面性能以及页面是否存在后台等等因素,有可能执行完 setTimeout 这个 task 之后,发现还没到渲染时机,所以 setTimeout 回调了几次之后才进行渲染

requestAnimationFrame 的使用场景

在大数据渲染过程中,比如表格的渲染,如果不进行一些性能策略处理,就会出现 UI 冻结现象,用户体验极差。有个场景,将后台返回的十万条记录插入到表格中,如果一次性在循环中生成 DOM 元素,会导致页面卡顿5s左右。这时候我们就可以用 requestAnimationFrame 进行分步渲染,确定最好的时间间隔,使得页面加载过程中很流畅。

            var total = 10000;
            var size = 100;
            var count = total / size;
            var done = 0;
            var ul = document.getElementById('list');

            function addItems() {
                var li = null;
                var fg = document.createDocumentFragment();
                for (var i = 0; i < size; i++) {
                    li = document.createElement('li');
                    li.innerText = 'item ' + (done * size + i);
                    fg.appendChild(li);
                }
                ul.appendChild(fg);
                done++;
                if (done < count) {
                    requestAnimationFrame(addItems);
                }
            };
            requestAnimationFrame(addItems);

CSS 动画原理

根据上面的原理我们知道,你眼前所看到图像正在以每秒 60 次的频率绘制,由于频率很高,所以你感觉不到它在绘制。而 动画本质就是要让人眼看到图像被绘制而引起变化的视觉效果,这个变化要以连贯的、平滑的方式进行过渡。 那怎么样才能做到这种效果呢? 60Hz 的屏幕每 16.7ms 绘制一次,如果在屏幕每次绘制前,将元素的位置向左移动一个像素,即1px,这样一来,屏幕每次绘制出来的图像位置都比前一个要差1px,你就会看到图像在移动;而由于人眼的视觉停留效应,当前位置的图像停留在大脑的印象还没消失,紧接着图像又被移到了下一个位置,这样你所看到的效果就是,图像在流畅的移动。这就是视觉效果上形成的动画。

  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值