window.requestAnimationFrame讲解-程序员宅基地

技术标签: 前端开发  css  html5  javascript  

为什么要说它,源于看到的一道面试题:问题是用js实现一个无限循环的动画。

首先想到的是定时器

<!doctype html>
<html lang="en">
<head>
    <title>Document</title>
    <style>
        #e{
    
            width: 100px;
            height: 100px;
            background: red;
            position: absolute;
            left: 0;
            top: 0;
            zoom: 1;
        }
    </style>
</head>
<body>
<div id="e"></div>
<script>


    var e = document.getElementById("e");
    var flag = true;
    var left = 0;

    function render() {
    
        if(flag == true){
    
            if(left>=100){
    
                flag = false
            }
            e.style.left = ` ${
      left++}px`
        }else{
    
            if(left<=0){
    
                flag = true
            }
            e.style.left = ` ${
      left--}px`
        }
    }
    setInterval(function(){
    
         render()
    },1000/60)

</script>
</body>
</html>

可以说是完美实现!

至于时间间隔为什么是1000/60,这是因为大多数屏幕渲染的时间间隔是每秒60帧。

既然setInterval可以搞定为啥还要用requestAnimationFrame呢?

不同之处在于,setInterval必须指定多长时间再执行,window.requestAnimationFrame()则是推迟到浏览器下一次重绘时就执行回调。重绘通常是 16ms 执行一次,不过浏览器会自动调节这个速率,比如网页切换到后台 Tab 页时,requestAnimationFrame()会暂停执行。

如果某个函数会改变网页的布局,一般就放在window.requestAnimationFrame()里面执行,这样可以节省系统资源,使得网页效果更加平滑。因为慢速设备会用较慢的速率重流和重绘,而速度更快的设备会有更快的速率。

直接上代码:

注意: requestAnimationFrame()在浏览器重绘前执行,所以要想执行requestAnimationFrame()必须要让浏览器触发重绘。

<!doctype html>
<html lang="en">
<head>
    <title>Document</title>
    <style>
        #e{
    
            width: 100px;
            height: 100px;
            background: red;
            position: absolute;
            left: 0;
            top: 0;
            zoom: 1;
        }
    </style>
</head>
<body>
<div id="e"></div>
<script>


    var e = document.getElementById("e");
    var flag = true;
    var left = 0;

    function render() {
    
        if(flag == true){
    
            if(left>=100){
    
                flag = false
            }
            e.style.left = ` ${
      left++}px`
        }else{
    
            if(left<=0){
    
                flag = true
            }
            e.style.left = ` ${
      left--}px`
        }
    }

    //requestAnimationFrame效果
    (function animloop() {
    
        render();
        window.requestAnimationFrame(animloop);
    })();

</script>
</body>
</html>

但是,怎么停止requestAnimationFrame?是否有类似clearInterval这样的类似方法?

答案是确定的。requestAnimationFrame()返回一个 long 整数,请求 ID ,是回调列表中唯一的标识,是个非零值,没别的意义。你可以传这个值给 window.cancelAnimationFrame() 以取消回调函数。

<!doctype html>
<html lang="en">
<head>
    <title>Document</title>
    <style>
        #e{
    
            width: 100px;
            height: 100px;
            background: red;
            position: absolute;
            left: 0;
            top: 0;
            zoom: 1;
        }
    </style>
</head>
<body>
<div id="e"></div>
<script>


    var e = document.getElementById("e");
    var flag = true;
    var left = 0;
    var rafId = null


    function render() {
    
        if(flag == true){
    
            if(left>=100){
    
                flag = false
            }
            e.style.left = ` ${
      left++}px`
        }else{
    
            if(left<=0){
    
                flag = true
            }
            e.style.left = ` ${
      left--}px`
        }
    }

    //requestAnimationFrame效果
    (function animloop(time) {
    
        console.log(time,Date.now())
        render();
        rafId = requestAnimationFrame(animloop);
        //如果left等于50 停止动画
        if(left == 50){
    
            cancelAnimationFrame(rafId)
        }
    })();

    //setInterval效果
    // setInterval(function(){
    
    //     render()
    // },1000/60)

</script>
</body>
</html>

MDN链接

总结:

	function animloop() {
    
        console.log('aa')
    }
    window.requestAnimationFrame(animloop);

浏览器其实一直在刷新,当给window.requestAnimationFrame传入一个回调函数的时候,那么就是告诉浏览器在渲染前执行一下这个回调函数。


    (function animloop(time) {
    
       	console.log('time', Date.now())
        rafId = requestAnimationFrame(animloop);
    })();

或者

<script>
    let i= 0;
    function clock() {
    
        console.log(i)
        window.requestAnimationFrame(clock);
    }
    window.requestAnimationFrame(clock);
</script>

上面这段代码只要一执行,那么就会停不下来。
原因是:我们可以把requestAnimationFrame想象成setTimeout,由于requestAnimationFrame并不是在所有的浏览器中都支持,那么我们可以写一个用setTimeout实现的polyfill,而setTimeout又是异步的,所以,进入异步队列后又调用那个回调,这样一直回调下去,所以能够一直执行。

如下:

// 这段代码不全
if (!window.requestAnimationFrame) {
    
	window.requestAnimationFrame = function(callback, element) {
    
	     var currTime = new Date().getTime();
	     var timeToCall = Math.max(0, 16 - (currTime - lastTime));
	     var id = window.setTimeout(function() {
     
		     	callback(currTime + timeToCall); 
		     }, timeToCall);
	     lastTime = currTime + timeToCall;
	     return id;
	};
}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/yexudengzhidao/article/details/119640866

智能推荐

Java-DBCP连接池使用方法_javaj dbcp连接池-程序员宅基地

文章浏览阅读543次。一、导包二、配置文件三、编写工具类_javaj dbcp连接池

iOS 导航栏背景颜色或透明度页面偏移问题修改适配_ios 导航栏设置透明 整体布局上移了-程序员宅基地

文章浏览阅读919次。当按照一下方法设置导航栏背景会导致页面向下偏移UINavigationBar * bar = [UINavigationBar appearance];[bar setBackgroundImage:[self createImageWithColor:MainColor] forBarMetrics:UIBarMetricsDefault];或bar.translucent = NO;这时候需要..._ios 导航栏设置透明 整体布局上移了

E01 -- CSS样式中 报错 { expectedcss(css-lcurlyexpected)-程序员宅基地

文章浏览阅读1.5w次,点赞5次,收藏3次。{ expectedcss(css-lcurlyexpected) 我发现这个错误是在使用rem布局的时候:使用less样式生成css文件中,css文件报错:发现错误发现我在媒体布局中没有写元素:导致字体大小不知道是给谁设置的导致生成css错误样式:改正:给less中字体大小加一个元素就好了:生成的css文件中样式:解决..._{ expectedcss(css-lcurlyexpected)

一分钟看懂MySQL的page数据页_mysql 记录修改后的数据页-程序员宅基地

文章浏览阅读1.4k次。MySQL存储引擎拆解MySQL记录存储页头页尾最大最小虚记录记录堆自由空间链表(已删除记录)未分配空间Slot区_mysql 记录修改后的数据页

hook(react) 兄弟组件传值_react hook 兄弟组件传值-程序员宅基地

文章浏览阅读7.6k次,点赞2次,收藏7次。hook 兄弟组件传值创建一个context对象.当react 渲染一个订阅你这个context 对象的组件, 这个组件会从组件树中离自身最近的那个匹配Provider(Provider 接收一个 value 属性, 传递给消费组件. 一个Provider可以和多个消费组件有对应关系. 多个Provider 也可以嵌套使用, 里层的会覆盖外层的数据 — 如:<MyContext.Pr..._react hook 兄弟组件传值

powershell执行脚本中的函数找不到函数_powershell 找不到函数-程序员宅基地

文章浏览阅读1.4k次,点赞2次,收藏2次。import-module C:\Windows\System32\WindowsPowerShell\v1.0\Functions.ps1需要先执行上面这句话,再调用脚本中的函数_powershell 找不到函数

随便推点

C++ 头文件系列(ostream)-程序员宅基地

文章浏览阅读1.2k次。1. 简介头文件ostream主要定义了一个输出流类模版basic_ostream,该模版继承自basic_ios模版。2. basic_ostream模版2.1 sentry类与basic_istream模版一样,basic_ostream也定义了一个sentry类,详见basic_istream::sentry。2.2 流定位函数seekp : 定位到指定位置。tellp : ..._code block的头文件是啥如果有ostream

Git手册 - 从SVN迁移到Git-程序员宅基地

文章浏览阅读78次。环境:Centos 6.x总的来说,从SVN迁移至Git共有以下几步:1)确保SVN的auth.conf文件里的每个user都在Git将会用来配置提交历史的文件里面有对应的名字和邮件地址2)创建一个本地的Git仓库3)将本地Git仓库连接到远程的SVN仓库4)配置Git的提交历史用户名5)开始从SVN获取代码6)将本地Git仓库连接到远程Git仓库7)推送本地仓库代码到远程仓..._svn 迁移 git config git svn fetch

【SVM回归预测】基于LibSVM实现多特征数据的预测_多特征的现有值预测未来值-程序员宅基地

文章浏览阅读7.9k次,点赞16次,收藏119次。本文介绍了如何利用机器学习中的SVM算法来解决生活中的问题,通过获取影响电动车价格的数据来建立一个预测电动车价格的模型。_多特征的现有值预测未来值

Bugku 宽带信息泄露 详解 MISC_bugku宽带信息泄露-程序员宅基地

文章浏览阅读2.3k次,点赞11次,收藏6次。宽带信息泄露一、题目二、思路三、复现四、总结我会不定时更新bugku的题目,和大家共同学习,披荆斩棘。日拱一卒,你的付出,终将使你强大。希望大家喜欢,多多点赞收藏谢谢。一、题目点击下载后为一个名伪config.bin的文件如下图。二、思路无论做任何事,要冷静多思,细致入微。以bin为结尾的文件是什么文件呢?bin文件:二进制文件,其用途依系统或应用而定。一种文件格式binary的缩写。一个后缀名为".bin"的文件,只是表明它是binary格式。比如虚拟光驱文件常用".bin"作_bugku宽带信息泄露

PowerBuilder从入门到精通(PB12.5)-程序员宅基地

文章浏览阅读3.4w次,点赞47次,收藏240次。创建一个Hello World程序 常用面板工具 基础 _powerbuilder

java计算机毕业设计多媒体素材网站(附源码+springboot+开题+论文+部署)-程序员宅基地

文章浏览阅读615次,点赞6次,收藏7次。其次,我们将开发高效的素材管理系统,实现素材的快速上传、审核和分类管理,确保网站内容的及时更新和质量可控。最后,我们将运用数据挖掘和机器学习等技术,对用户的行为和偏好进行分析,实现个性化的素材推荐功能,提升用户的满意度和忠诚度。本研究的意义在于,通过构建一个高效、便捷、全面的多媒体素材网站,实现多媒体素材的集中展示、分类管理和高效检索,为用户提供一站式的素材获取服务。根据素材的类型和特点,我们将设计合理的分类体系,并实现素材的上传、审核、分类和展示功能,确保用户能够方便地浏览和搜索到所需的素材。

推荐文章

热门文章

相关标签