• 基于脚本的动画的计时控制(“requestAnimationFrame”)(转)


     requestAnimationFrame 方法的支持,该方法通过在系统准备好绘制动画帧时调用该帧,从而为创建动画网页提供了一种更平滑更高效的方法。在此 API 之前,使用 setTimeout 和 setInterval 绘制的动画并没有为 Web 开发人员提供有效的方法来规划动画的图形计时器。这导致了动画过度绘制,浪费 CPU 周期以及消耗额外的电能等问题。而且,即使看不到网站,特别是当网站使用背景选项卡中的页面或浏览器已最小化时,动画都会频繁出现。

    当动画使用分辨率为 10ms 的 JavaScript 计时器绘制动画时,计时可能不匹配,如下所示。

    上面一行表示大多数监视器上显示的 16.7ms 显示频率,而下面一行表示通常的 10ms setTimeout。每个第三个图形都无法绘制(由红色箭头指示),因为在显示器刷新间隔之前发生了其他绘制请求。这种过度绘制的情况会导致动画断续显示,因为所有第三帧都会丢失。这种计时器分辨率的降低也会对电池使用寿命造成负面影响,并会降低其他应用的性能。

    requestAnimationFrame 方法(在万维网联合会 (W3C) 的针对基于脚本的动画的计时控制规范中定义)可以解决丢失帧的问题,因为它使应用能够在浏览器需要更新页面显示时(而且仅在这种情况下)获得通知。 因此,应用可与浏览器的绘制时间间隔保持完全一致,并且仅使用适量的资源。从 setTimeout 切换到 requestAnimationFrame 非常容易,因为它们都规划单个回调。要实现持续的动画,请在调用动画函数后再次调用 requestAnimationFrame。

    使用方法

    要使用这个新的 API,只需使用回调函数调用 requestAnimationFrame 即可。计时由系统处理

    var handle = requestAnimationFrame(renderLoop);

    这会影响你的第一个重画。若要保持动画继续运行,则需要从回调函数(如此处的 renderLoop)中再次调用 requestAnimationFrame

    示例:

    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <title></title>
        <meta charset="utf-8" />
        <style>
            #animated {
                position:absolute;
                top:100px;
                padding:50px;
                background:crimson;
                color:white;
            }
        </style>
    </head>
    <body>
        <div id="animated">Hello there.</div>
        <script>
            var elem = document.getElementById('animated');
            var handle = 0;
            var lPos = 0;
            renderLoop();
            function renderLoop() {
                elem.style.left = ((lPos += 3) % 800) + 'px';
                handle = window.requestAnimationFrame(renderLoop);
            }
            elem.addEventListener('click', function () {
                if (handle) {
                    window.cancelAnimationFrame(handle);
                    handle = null;
                } else {
                    renderLoop();
                }
            },false)
        </script>
    </body>
    </html>

    回调函数中的时间

    你可以使用回调函数对几乎所有内容(如 SVG、Canvas 或此处所示的 CSS 属性)设置动画。回调函数具有一个传入 time 参数,该参数表示调用回调函数的时间。它是一个 DOMHighResTimeStamp,是从页面导航开始时测量的高精确度时间。DOMHighResTimeStamp 以毫秒为单位,精确到千分之一毫秒。此时间值不直接与 Date.now() 进行比较,后者测量自 1970 年 1 月 1 日至今以毫秒为单位的时间。如果你希望将 time 参数与当前时间进行比较,请使用当前时间的 window.performance.now。将时间值从 DOMTimeStamp 更改为 DOMHighResTimeStamp 是 W3C 针对基于脚本动画计时控制规范的最新编辑草案中的最新更改,并且某些供应商仍将其作为 DOMTimeStamp 实现。较早版本的 W3C 规范使用 DOMTimeStamp,允许你将 Date.now 用于当前时间。

    浏览器支持

    如上所述,某些浏览器供应商可能仍实现 DOMTimeStamp 参数,或者尚未实现 window.performance.now 计时函数。由于 W3C 规范尚未最后定稿,因此其他浏览器制造商已创建其自己的 requestAnimationFrame 和 cancelAnimationFrame 前缀实现。本例提供了一个我们的动画程序版本,该程序使用 Time 移动 <div> 元素并在多个浏览器上使用。

    示例2:

    <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title></title>
        <meta charset="utf-8" />
        <style>
            #animated {
                position: absolute;
                top: 100px;
                padding: 50px;
                background: crimson;
                color: white;
            }
        </style>
    </head>
    <body>
        <div id="animated">Hello there.</div>
        <script>
            var requestID = 0;
            var starttime = 0;
            var lpos = 0;
            var elem;
            function init() {
                elem = document.getElementById('animated');
    
                elem.addEventListener('click', function () {
                    start();
                }, false);
            }
            init();
    
            //循环执行方法
            function render() {
                elem.style.left=((lpos += 3) % 600) + 'px';
                requestID = window.requestAFrame(render);
            }
            //开始
            function start() {
                if (window.performance.now) {
                    starttime = window.performance.now();
                } else {
                    starttime = Date.now();
                }
                requestID = window.requestAFrame(render);
            }
            //停止
            function stop() {
                if (requestID)
                    window.cancelAFrame(requestID);
            }
            //兼容针处理
            window.requestAFrame = (function () {
                return window.requestAnimationFrame||
                    window.webkitRequestAnimationFrame||
                    window.mozRequestAnimationFrame||
                    window.oRequestAnimationFrame||
                    //如果不支持使用 setTimeOut
                    function (callback) {
                        return window.setTimeout(callback,1000/60); //shoot for 60 fps
                    }
            })();
            //兼容针注销 
            window.cancelAFrame = (function () {
                return window.cancelAnimationFrame||
                    window.webkitCancelAnimationFrame||
                    window.mozCancelAnimationFrame||
                    window.oCancelAnimationFrame||
                    function (id) {
                        window.clearTimeout(id);
                    }
            })();
        </script>
    </body>
    </html>
  • 相关阅读:
    [PyTorch 学习笔记] 8.1 图像分类简述与 ResNet 源码分析
    [PyTorch 学习笔记] 7.3 使用 GPU 训练模型
    [PyTorch 学习笔记] 7.2 模型 Finetune
    [PyTorch 学习笔记] 7.1 模型保存与加载
    [PyTorch 学习笔记] 6.2 Normalization
    【成都GamEver游戏公司诚邀服务器伙伴】【7~15k一年4次项目奖金】
    如何彻底隐藏iOS7应用的status bar
    更新证书错误Code Sign error: Provisioning profile ‘XXXX'can't be found
    leetcode@ [273] Integer to English Words (String & Math)
    geeksforgeeks@ Largest Number formed from an Array
  • 原文地址:https://www.cnblogs.com/tianma3798/p/5183166.html
Copyright © 2020-2023  润新知