zoukankan      html  css  js  c++  java
  • JavaScript进阶【五】利用JavaScript实现动画的基本思路

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <style>
            #div {
                width: 100px;
                height: 100px;
                background-color: #00a8c6;
                position: absolute;
            }
    
            #block {
                width: 80px;
                height: 80px;
                background-color: #0a001f;
                position: absolute;
                margin-left: 120px;
            }
    
            #blockTwo {
                width: 80px;
                height: 80px;
                background-color: #00FA9A;
                position: absolute;
                margin-left: 190px;
            }
    
            #ball {
                width: 100px;
                height: 100px;
                border-radius: 50px;
                border: solid rgb(100, 100, 100) 1px;
                position: absolute;
                margin-top: 100px;
                background-color: #1b1b1b;
            }
    
            #car {
                width: 80px;
                height: 80px;
                background-color: #4B0082;
                position: absolute;
                margin-left: 220px;
            }
    
            #stone {
                width: 50px;
                height: 50px;
                border-radius: 25px;
                border: solid rgb(100, 100, 100) 1px;
                position: absolute;
                margin-top: 150px;
                margin-left: 150px;
                background-color: #8B0000;
            }
    
            #SinMove {
                width: 50px;
                height: 50px;
                border-radius: 25px;
                border: solid rgb(100, 100, 100) 1px;
                position: absolute;
                margin-top: 800px;
                margin-left: 220px;
                background-color: #00FA9A;
            }
    
            #CircleMove {
                width: 50px;
                height: 50px;
                background-color: #4B0082;
                margin-top: 500px;
                margin-left: 500px;
            }
    
            #moveAny {
                width: 100px;
                height: 100px;
                border-radius: 50px;
                border: solid rgb(100, 100, 100) 1px;
                position: absolute;
                margin-top: 800px;
                margin-left: 220px;
                background-color: #7FFF00;
                text-align: center;
                padding-top: 20px;
            }
    
            #controlPan {
                margin-top: 400px;
                border: 2px solid blue;
                height: 400px;
                width: auto;
            }
        </style>
    
        <!--1.实现一个简单的div块元素-->
        <script>
            var id;
    
            var direct = -1;
            var times = 0;
    
            function step() {
                times++;
    
                // 获取这个块元素
                var div = document.getElementById("div");
    
                console.log(div.offsetLeft);
                if (div.offsetLeft == 800) {
                    direct = 0;
                } else if (div.offsetLeft == 8) {
                    direct = 1;
                }
    
                if (direct == 1) {
                    // 设置这个div元素向左的偏移量
                    var temp = div.offsetLeft + 2;
                    // 设置坐标的距离
                    div.style.left = temp + "px";
                } else if (direct == 0) {
                    // 设置这个div元素向左的偏移量
                    var temp = div.offsetLeft - 2;
                    // 设置坐标的距离
                    div.style.left = temp + "px";
                }
    
                //setTimeout一样,要手动调用才能实现连续动画。
                id = window.requestAnimationFrame(step);  //返回值是一个id,可以通过这个id来取消
    
                // 复杂的计算
                for (var i = 0; i < 50; i++) {
                    console.log("再牛逼的定时器也得等到我执行完才能执行");
                }
    
    
                //取消回调函数
                if (times == 0) {
                    window.cancelAnimationFrame(id);
                }
    
            }
    
            // 第一次调用
            //id = window.requestAnimationFrame(step);
    
    
        </script>
    
        <!--2.setTimeoutsetInterval深入理解-->
        <script>
            /*console.log("1");
            setTimeout(function () {
                console.log("3");
            }, 0);
            console.log("2");  // 输出: 1 2 3*/
            // 2. 使用动画的正确姿势,动画其实是位移关于时间的函数:s=f(t)
            // 解决动画变慢的问题:把动画与时间关联起来
            function startAnimation() {
                var startTime = Date.now();
                requestAnimationFrame(function change(time) {
                    var current = Date.now() - startTime;
                    console.log("动画已经执行的时间为:" + current);
                    requestAnimationFrame(startAnimation);
                });
            }
    
            //startAnimation();
    
            //  动画通常情况下有终止时间,如果是循环动画,我们也可以看做特殊的——当动画达到终止时间之后,重新开始动画。因此,我们可以将动画时间归一(Normalize)表示:
            //duration 是动画执行时间   isLoop是否为循环执行。
            function startAnimation(duration, isLoop) {
                var startTime = Date.now();
    
                requestAnimationFrame(function change() {
                    // 动画已经用去的时间占总时间的比值
                    var p = (Date.now() - startTime) / duration;
                    //console.log(p);
    
                    if (p >= 1.0) {
                        if (isLoop) { // 如果是循环执行,则开启下一个循环周期。并且把开始时间改成上个周期的结束时间
                            startTime += duration;
                            p -= 1.0; //动画进度初始化
                        } else {
                            p = 1.0;    //如果不是循环,则把时间进度至为 1.0 表示动画执行结束
                        }
                    }
                    console.log("动画已执行进度", p);
                    if (p < 1.0) { //如果小于1.0表示动画还诶有值完毕,继续执行动画。
                        requestAnimationFrame(change);
                    }
                });
            }
    
            //startAnimation(100, true);
    
    
            // 示例1:用时间控制动画周期精确到2s        function blockClick(obj) {
                var block = document.getElementById("block");
    
    
                var self = obj,
                    startTime = Date.now(),
                    duration = 2000;
                // 添加一个动画
                setInterval(function () {
                    var p = (Date.now() - startTime) / duration;
                    // 时间已经完成了2000的比例,则360度也是进行了这么个比例。
                    self.style.transform = "rotate(" + (360 * p) + "deg)";
                }, 100);
    
            }
    
            // 示例2:让滑块在2秒内向右匀速移动600px
            function blockTwoClick(obj) {
                var self = obj;
                var startTime = Date.now(),
                    distance = 600,
                    duration = 2000;
    
                requestAnimationFrame(function step(time) {
                    var p = Math.min(1.0, (Date.now() - startTime) / duration);
                    //沿着X方向运动
                    self.style.transform = "translateX(" + (distance * p) + "px)";
                    // 如果动画没有执行完毕, 就继续执行
                    if (p < 1.0) {
                        requestAnimationFrame(step);
                    }
                })
            };
    
            // 实例3: 实现小球的自由落体运动
            function ballClick(obj) {
                var self = obj,
                    startTime = Date.now(),
                    distance = 1000,
                    duration = 1500;
                requestAnimationFrame(function step() {
                    var p = Math.min(1.0, (Date.now() - startTime) / duration);
                    self.style.transform = "translateY(" + (distance * p * p) + "px)";
                    if (p < 1.0) requestAnimationFrame(step);
                });
    
            }
    
    
            // 实例4 : 实现汽车的匀减速运动
            function carClick(obj) {
                var self = obj, startTime = Date.now(),
                    distance = 1000, duration = 2000;
                requestAnimationFrame(function step() {
                    var p = Math.min(1.0, (Date.now() - startTime) / duration);
                    self.style.transform = "translateX("
                        + (distance * p * (2 - p)) + "px)";
                    if (p < 1.0) requestAnimationFrame(step);
                });
    
            }
    
            // 实例5 : 水平抛物运动
            function stoneClick(obj) {
                var self = obj, startTime = Date.now(),
                    disX = 1000, disY = 1000,
                    duration = Math.sqrt(2 * disY / 10 / 9.8) * 1000;   // 落到地面需要的时间  单位ms
                //假设10px1米,disY = 100
                requestAnimationFrame(function step() {
                    var p = Math.min(1.0, (Date.now() - startTime) / duration);
                    var tx = disX * p;  //水平方向是匀速运动
                    var ty = disY * p * p;  //垂直方向是匀加速运动
    
                    self.style.transform = "translate("
                        + tx + "px" + "," + ty + "px)";
                    if (p < 1.0) requestAnimationFrame(step);
                });
    
            }
    
    
            // 实例6 : 正弦曲线运动
            function SinMoveClick(obj) {
                var self = obj, startTime = Date.now(),
                    distance = 800,
                    duration = 5000;
    
                requestAnimationFrame(function step() {
                    var p = Math.min(1.0, (Date.now() - startTime) / duration);
                    var ty = distance * Math.sin(2 * Math.PI * p);
                    var tx = 2 * distance * p;
    
                    self.style.transform = "translate("
                        + tx + "px," + ty + "px)";
                    if (p < 1.0) requestAnimationFrame(step);
                });
    
            }
    
            // 实例7 : 圆周运动
            function CircleMoveClick(obj) {
                var self = obj,
                    startTime = Date.now(),
                    r = 100,
                    duration = 2000;
    
                requestAnimationFrame(function step() {
                    var p = Math.min(1.0, (Date.now() - startTime) / duration);
                    var tx = r * Math.sin(2 * Math.PI * p),
                        ty = -r * Math.cos(2 * Math.PI * p);
    
                    self.style.transform = "translate(" +
                        tx + "px," + ty + "px)";
                    requestAnimationFrame(step);
                });
            }
    
    
            // 实现动画算子的封装
            // pow() 方法可返回 x  y 次幂的值
            var pow = Math.pow,
                BACK_CONST = 1.70158;
            // t指的的是动画进度  前面的p
            Easing = {
                // 匀速运动
                linear: function (t) {
                    return t;
                },
                // 加速运动
                easeIn: function (t) {
                    return t * t;
                },
                // 减速运动
                easeOut: function (t) {
                    return (2 - t) * t;
                },
                //先加速后减速
                easeBoth: function (t) {
                    return (t *= 2) < 1 ? .5 * t * t : .5 * (1 - (--t) * (t - 2));
                },
                // 4次方加速
                easeInStrong: function (t) {
                    return t * t * t * t;
                },
                // 4次方法的减速
                easeOutStrong: function (t) {
                    return 1 - (--t) * t * t * t;
                },
                // 先加速后减速,加速和减速的都比较剧烈
                easeBothStrong: function (t) {
                    return (t *= 2) < 1 ? .5 * t * t * t * t : .5 * (2 - (t -= 2) * t * t * t);
                },
                //
                easeOutQuart: function (t) {
                    return -(Math.pow((t - 1), 4) - 1)
                },
                // 指数变化 加减速
                easeInOutExpo: function (t) {
                    if (t === 0) return 0;
                    if (t === 1) return 1;
                    if ((t /= 0.5) < 1) return 0.5 * Math.pow(2, 10 * (t - 1));
                    return 0.5 * (-Math.pow(2, -10 * --t) + 2);
                },
                //指数式减速
                easeOutExpo: function (t) {
                    return (t === 1) ? 1 : -Math.pow(2, -10 * t) + 1;
                },
                // 先回弹,再加速
                swingFrom: function (t) {
                    return t * t * ((BACK_CONST + 1) * t - BACK_CONST);
                },
    
                // 多走一段,再慢慢的回弹
                swingTo: function (t) {
                    return (t -= 1) * t * ((BACK_CONST + 1) * t + BACK_CONST) + 1;
                },
    
                //弹跳
                bounce: function (t) {
                    var s = 7.5625,
                        r;
    
                    if (t < (1 / 2.75)) {
                        r = s * t * t;
                    } else if (t < (2 / 2.75)) {
                        r = s * (t -= (1.5 / 2.75)) * t + .75;
                    } else if (t < (2.5 / 2.75)) {
                        r = s * (t -= (2.25 / 2.75)) * t + .9375;
                    } else {
                        r = s * (t -= (2.625 / 2.75)) * t + .984375;
                    }
    
                    return r;
                }
            };
    
            /*
          参数1:动画的执行时间
          参数2:动画执行的时候的回调函数(动画执行的要干的事情)
          参数3:动画算子. 如果没有传入动画算子,则默认使用匀速算子
         */
            function Animator(duration, progress, easing) {
                this.duration = duration;
                this.progress = progress;
                this.easing = easing || function (p) {
                    return p
                };
            }
    
            Animator.prototype = {
                /*开始动画的方法,
                 参数:一个布尔值
                 true表示动画不循环执行。
                */
                start: function (finished) {
                    /*动画开始时间*/
                    var startTime = Date.now();
                    /*动画执行时间*/
                    var duration = this.duration,
                        self = this;
                    /*定义动画执行函数*/
                    requestAnimationFrame(function step() {
                        /*得到动画执行进度*/
                        var p = (Date.now() - startTime) / duration;
                        /*是否执行下一帧动画*/
                        var next = true;
                        /*判断动画进度是否完成*/
                        if (p < 1.0) {
                            self.progress(self.easing(p), p);   //执行动画回调函数,并传入动画算子的结果和动画进度。
                        } else {
                            if (finished) {  //判断是否停止动画。如果是true代表停止动画。
                                next = false;
                            } else {
                                startTime = Date.now();
                            }
                        }
                        // 如果nexttrue执行下一帧动画
                        if (next) requestAnimationFrame(step);
                    });
                }
            };
    
            function ChangeState() {
                var self = document.getElementById("moveAny");
                // 新建一个动画
                new Animator(2000, function (p) {
                    self.style.top = 500 * p + "px";
                }, Easing.easeBoth).start(false);
    
            }
    
        </script>
    </head>
    <body>
    <div style="border: 2px solid red">
        <!--动画实现方式:通过操作JavaScript间接操作CSS样式,每隔一段时间更新一次;-->
        <div id="div"></div>
    
        <div id="block" onclick="blockClick(this)"></div>
        <div id="blockTwo" onclick="blockTwoClick(this)"></div>
    
        <div id="ball" onclick="ballClick(this)"></div>
        <div id="car" onclick="carClick(this)"></div>
        <div id="stone" onclick="stoneClick(this)"></div>
        <div id="SinMove" onclick="SinMoveClick(this)"></div>
        <div id="CircleMove" onclick="CircleMoveClick(this)"></div>
    </div>
    
    
    <div id="moveAny">我是一个可以做任意运动的物体</div>
    <div id="controlPan">控制面板
        <button onclick="ChangeState(this)">切换运动状态</button>
    </div>
    </body>
    </html>
  • 相关阅读:
    P1144 最短路计数 题解 最短路应用题
    C++高精度加减乘除模板
    HDU3746 Teacher YYF 题解 KMP算法
    POJ3080 Blue Jeans 题解 KMP算法
    POJ2185 Milking Grid 题解 KMP算法
    POJ2752 Seek the Name, Seek the Fame 题解 KMP算法
    POJ2406 Power Strings 题解 KMP算法
    HDU2087 剪花布条 题解 KMP算法
    eclipse创建maven项目(详细)
    maven的作用及优势
  • 原文地址:https://www.cnblogs.com/52tech/p/9325102.html
Copyright © 2011-2022 走看看