requestAnimationFrame 持续动画效果
1. requestAnimationFrame 概述
requestAnimationFrame 是浏览器用于定时循环操作的一个API, 类似于setTimeout, 主要用途是按帧对网页进行重绘.
设置这个API的目的就是为了让各种网页动画效果 (DOM动画, Canvas动画, SVG动画, WebGL动画) 能有一个统一的刷新机制, 从而节省系统资源, 提高系统性能, 改善视觉效果. 使用这个API, 就是告诉浏览器希望执行一个动画, 让浏览器在下一个动画帧对网页进行一次网页重绘.
requestAnimationFrame 的优势在于, 充分利用了显示器的刷新机制, 比较节省系统的资源, 显示器的固定刷新频率是 60HZ或者75HZ, 也就是说, 每秒最多能绘制60次或者75次, 这个API的思想就是与这个刷新频率保持同步, 利用这个刷新频率对网页进行重绘. 另外, 使用这个API, 当浏览器不处于当前标签页, 就会自动停止刷新.
缺点是, requestAniamtionFrame 是在主线程上完成的, 这就意味着, 一旦主线程非常繁忙, requestAnimationFrame的动画效果会大打折扣.
requestAnimationFrame 使用一个回调函数作为参数, 这个回调函数在流浪器重绘之前调用
var requestID = window.requestAnimationFrame(calback)
目前主要浏览器都支持这个API, 查看更多兼容性

即使主流浏览器都支持, 但还是要检查浏览器是否支持, 而且各浏览器都带有前缀, 如果不支持, 就使用setTimeout模拟该方法
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();
上面的代码按照1秒60次来模拟requestAnimationFrame, 使用的时候只需要反复调用即可
function repeatOften() {
// Do whatever
requestAnimationFrame(repeatOften);
}
requestAnimationFrame(repeatOften);
2. cancelAnimationFrame 方法
cancelAnimationFrame方法用于取消重绘
window.cancelAnimationFrame(requestID)
他的参数是requestAnimationFrame返回的一个代表任务ID的整数值
var globalID;
function repeatOften() {
$("<div />").appendTo("body");
globalID = requestAnimationFrame(repeatOften);
}
$("#start").on("click", function() {
globalID = requestAnimationFrame(repeatOften);
});
$("#stop").on("click", function() {
cancelAnimationFrame(globalID);
});
上面的代码就是不断的网body中添加div, 知道用户点击stop为止
3. 实例
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>request</title>
<style type="text/css">
#anim {
height: 100px;
width: 100px;
border-radius: 6px;
background-color: #f66;
color: #fff;
margin-top: 50px;
position: absolute;
}
</style>
</head>
<body>
<div id="anim">运动区域</div>
<button id="start">开始</button>
<button id="stop">停止</button>
</body>
<script type="text/javascript">
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback, element) {
window.setTimeout(callback, 1000 / 60);
};
})();
var anim = document.getElementById('anim');
var start = document.getElementById('start');
var stop = document.getElementById('stop');
var startTime = undefined;
var requestId = undefined;
function render(time) {
if (time === undefined) {
time = Date.now();
}
if (startTime === undefined) {
startTime = time;
}
anim.style.left = ((time - startTime) / 10 % 500) + 'px';
}
start.onclick = function() {
(function animloop() {
render();
requestId = requestAnimationFrame(animloop, anim)
})();
}
stop.onclick = function() {
window.cancelAnimationFrame(requestId);
}
</script>
</html>
下面看一个关于requestAnimationFrame的面试题
如何一次性加载几万条数据,要求不卡住界面?
道题考察了如何在不卡住页面的情况下渲染数据,也就是说不能一次性将几万条都渲染出来,而应该一次渲染部分 DOM,那么就可以通过 requestAnimationFrame 来每 16 ms 刷新一次。
<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<ul>控件</ul>
<script>
setTimeout(() => {
// 插入十万条数据
const total = 100000
// 一次插入 20 条,如果觉得性能不好就减少
const once = 20
// 渲染数据总共需要几次
const loopCount = total / once
let count = 0
let requestId = 0
let ul = document.querySelector("ul");
function add() {
// 优化性能,插入不会造成回流
const fragment = document.createDocumentFragment();
for (let i = 0; i < once; i++) {
const li = document.createElement("li");
count += 1
li.innerText = Math.floor(count);
fragment.appendChild(li);
}
ul.appendChild(fragment);
loop();
}
function loop() {
if (count < total) {
requestId = window.requestAFrame(add);
} else {
window.cancelAFrame(requestId)
}
}
loop();
}, 0);
// handle multiple browsers for requestAnimationFrame()
window.requestAFrame = (function () {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
// if all else fails, use setTimeout
function (callback) {
return window.setTimeout(callback, 1000 / 60); // shoot for 60 fps
};
})(); // handle multiple browsers for cancelAnimationFrame()
window.cancelAFrame = (function () {
return window.cancelAnimationFrame ||
window.webkitCancelAnimationFrame ||
window.mozCancelAnimationFrame ||
window.oCancelAnimationFrame ||
function (id) {
window.clearTimeout(id);
};
})();
</script>
</body>
</html>
参考链接
https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestAnimationFrame
http://www.jb51.net/article/92994.htm
https://developer.mozilla.org/zh-CN/docs/Web/CSS/animation
requestAnimationFrame 持续动画效果的更多相关文章
- 使用requestAnimationFrame做动画效果二
3月是个好日子,渐渐地开始忙起来了,我做事还是不够细心,加上感冒,没精神,今天差点又出事了,做过的事情还是要检查一遍才行,哎呀. 使用requestAnimationFrame做动画,我做了很久,终于 ...
- 使用requestAnimationFrame做动画效果一
最近学习了requestAnimationFrame,看了张鑫旭直白易懂,但是某些地方语言过于裸露的文章http://www.zhangxinxu.com/wordpress/2013/09/css3 ...
- window.requestAnimationFrame()的使用,处理更流畅的动画效果
https://blog.csdn.net/w2765006513/article/details/53843169 window.requestAnimationFrame()的使用 2016年12 ...
- jquery动画效果中,避免持续反应用户的连续点击
一.某些动画效果中,避免持续连续反应用户的连续点击(这标题真不好描述) 意思就是指用户点击速度很快,完成一次效果的时间不能很快结束的话,就会出现用户不点击了,效果还在持续.看下面例子就明白了,手风琴效 ...
- Android动画效果之自定义ViewGroup添加布局动画
前言: 前面几篇文章介绍了补间动画.逐帧动画.属性动画,大部分都是针对View来实现的动画,那么该如何为了一个ViewGroup添加动画呢?今天结合自定义ViewGroup来学习一下布局动画.本文将通 ...
- Android动画效果之Frame Animation(逐帧动画)
前言: 上一篇介绍了Android的Tween Animation(补间动画) Android动画效果之Tween Animation(补间动画),今天来总结下Android的另外一种动画Frame ...
- 详解用CSS3制作圆形滚动进度条动画效果
主 题 今天手把手教大家用CSS3制作圆形滚动进度条动画,想不会都难!那么,到底是什么东东呢?先不急,之前我分享了一个css实现进度条效果的博客<CSS实现进度条和订单进度条>,但是呢, ...
- requestAnimationFrame制作动画:旋转风车
在以往,我们在网页上制作动画效果的时候,如果是用javascript实现,一般都是通过定时器和间隔来实现的,出现HTML5之后,我们还可以用CSS3 的transitions和animations很方 ...
- tween.js是一款可生成平滑动画效果的js动画库。tween.js允许你以平滑的方式修改元素的属性值。它可以通过设置生成各种类似CSS3的动画效果。
简要教程 tween.js是一款可生成平滑动画效果的js动画库.相关的动画库插件还有:snabbt.js 强大的jQuery动画库插件和Tweene-超级强大的jQuery动画代理插件. tween. ...
随机推荐
- 循环神经网络-RNN入门
首先学习RNN需要一定的基础,即熟悉普通的前馈神经网络,特别是BP神经网络,最好能够手推. 所谓前馈,并不是说信号不能反向传递,而是网络在拓扑结构上不存在回路和环路. 而RNN最大的不同就是存在环路. ...
- static关键字(修饰函数、局部变量、全局变量)
在C语言中,static的字面意思很容易把我们导入歧途,其实它的作用有三条. (1)先来介绍它的第一条也是最重要的一条:隐藏. 当我们同时编译多个文件时,所有未加static前缀的全局变量和函数都具有 ...
- L264 how cats are psychopaths
When Becky Evans started studying cat-human relationships, she kept hearing, over and over again, ab ...
- WIN10-缩放与布局
HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics\AppliedDPI230%----- 221225%----- 218220%----- ...
- js继承中,原型属性的继承探究
最近研究了js的继承,看了幻天芒的文章http://www.cnblogs.com/humin/p/4556820.html#3947420,明白了最好是使用apply或call方法来实现继承. 已知 ...
- 24点小游戏app宣传文案
24点小游戏app宣传文案 游戏背景 24点小游戏是传统的扑克牌游戏,是通过扑克牌来完成的竞争性智力游戏,除了希望能够消磨我们的空闲时间,加强同学们的临机和速算能力,还能够促进我们每个人的大脑和逻辑性 ...
- delphi-search-path-vs-library-path-vs-browsing-path
https://stackoverflow.com/questions/812042/delphi-search-path-vs-library-path-vs-browsing-path Del ...
- 《统计学习方法》笔记(3):k近邻
k近邻(KNN)是相对基本的机器学习方法,特点是不需要建立模型,而是直接根据训练样本的数据对测试样本进行分类. 1.k近邻的算法? 算法对测试样本进行分类的一般过程如下: 1)根据给定的k值,搜索与测 ...
- winform 点击控件拖动窗体
private Point mPoint = new Point(); private void 选择控件_MouseDown(object sender, MouseEventArgs e) { m ...
- 当超强台风“山竹”即将冲进南海,Power BI 你怎么看?
这个周末“山竹 ”强势来袭!很多人的目光都在关注暴力水果“山竹”,这个号称70年最强最大风力超17级 台风“山竹”今天就已经在小悦家窗台肆虐咆哮了一天了!不知其他的小伙伴们是不是好好的一个周末就只能被 ...