JavaScript 动画原理

🌙
手机阅读
本文目录结构

基础动画库以动画原理

最动画要做绝对定位,写left,写top;定好位置;

动画主要是从5个方向改变:

  • 宽度 (width)
  • 高度 (height)
  • 水平 (left)
  • 垂直 (top)
  • 透明度 (opacity)

JS写动画,主要是学逻辑关系,深入研究闭包作用域;并不是完全用JS写动画。CSS3做这个会更好;

this关键字:

this是谁,和在哪儿定义没有关系,只和在哪儿执行有关系,看它的执行主体是谁;自执行函数是在window,所以this是window;

(只有执行的时候才能知道this是谁;)

动画要考虑临界值的问题;每走一步之前先做判断,判断当前的位置+步长,是否大于等于目标值;如果大于等于目标值;则停在目标值上;

定时器的清理;定时器开启之前要记得清理,这样可以避免作用域累计;示例代码如下

clearTimeout(timer);//timer里储存的是定时器的序列号,1,2,3,4,5,6,7,8,9之类的;代表某个定时器;清除的就是定时器的序列号;
//没开一次定时器,就会产生一个定时器的序列号;
    var cur=getCss(ele,"left");
    if(cur<target){//当前位置小于目标值;
        if(cur+11>=target){//临界值的判断;
            ele.style.left=target+"px";
        }else{
            ele.style.left=getCss(ele,"left")+11+"px";
        }
        timer=window.setTimeout(function(){move(ele,target)},30)
  • 如果当前起始的位置小于我们的目标值的话,我们需要往右走,如果当前起始的位置大于我们的目标值的话,往左走,相等的话不走
    
  • 不管方向,都需要做临界判断,为了保障临界点的准确性,需要在判断的时候加上我们的步长
    

    动画中的几部分:

  1. 开始位置、结束位置、总距离;(总距离=结束位置-开始位置)
    
  2. 总运动时间、定时器间隔时间 、步长 ;(步长=(总距离/总运动时间)*定时器间隔时间)
    
  3. 运动的方式:匀速、减速、加速、变速
    

文字介绍2

动画部分

最动画要做绝对定位,写left,写top;定好位置;

动画主要是从5个方向改变:

  • 宽度 (width)
  • 高度 (height)
  • 水平 (left)
  • 垂直 (top)
  • 透明度 (opacity)

JS写动画,主要是学逻辑关系,深入研究闭包作用域;并不是完全用JS写动画。CSS3做这个会更好;

同步和异步编程

js是单线程的编程方法;

  • 同步:上面事情等待,在此期间我要一直等,只有这件事做完才能做下件事情
  • 异步:模拟多线程,上面的事情正在等待中,我们不需要等它,继续做下面的事情,当下面的事情做完了,然后我们发现上面的事情也等待完成了,在执行上面的事情

同步编程的例子:

 function fn() {
 for (var i = 0; i < 1000; i++) {
 }
 console.log(i);//只有循环完成才能输出i
 return i;
 }
 var c = fn();
 console.log(c);//只有fn执行完成后才会输出c

异步编程例子:

1、所有的事件绑定都是异步编程
oDiv.onclick=function(){}
window.onload=function(){}
console.log(100);
2、定时器都是异步编程
定时器的等待时间是有最小值的 每个浏览器都有一个最小值,即使你写的是0,也不是立即执行;定时器和别的代码是两个频道的。异步执行;作用域和预解释的时候有总结过;
var num = 12;
window.setTimeout(function () {
    num++;
    console.log(num);
}, 5);
for (var i = 0; i < 10000; i++) {//这个循环时间肯定大于5ms,但是也是先从上倒下执行,只有下面的代码都执行完成,才会返回头看定时器是否到时间,到了在执行定时器里面的
}
console.log(num);
//先输出12然后在输出13;说明是先执行完for循环和后面的打印;然后才切到定时器的执行的;

动画中的几部分:

  1. 开始位置、结束位置、总距离;(总距离=结束位置-开始位置)
    
  2. 总运动时间、定时器间隔时间 、步长 ;(步长=(总距离/总运动时间)*定时器间隔时间)
    
  3. 运动的方式:匀速、减速、加速、变速
    

代码1

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>从左向右运动</title>
    <style>
        #div1{
            width: 200px;height: 200px;background:red;position: absolute;left: 0;top:0;
        }
    </style>
</head>
<body>
<div id="div1"></div>
</body>
</html>
<script>
    var oDiv=document.getElementById("div1");
    oDiv.onclick=function(){
        move(this,600)
    };
    function move(ele,target){
        if(getCss(ele,"left")<target){
            ele.style.left=getCss(ele,"left")+5+"px";
            window.setTimeout(function(){move(ele,target)},30)
        }
    };
    function getCss(ele,attr){
        //变量未定义不能直接用,如果相判断一个变量是否存在可以typeof;
        //属性未定义可以直接使用;
        if(typeof getComputedStyle){
            return parseFloat(getComputedStyle(ele,null)[attr]);
        }else{
            return parseFloat(attr.currentStyle[attr]);
        }
    };

</script>

代码2

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>从右向左运动</title>
    <style>
        ul,li{list-style: none;}
        #div1{
            width: 200px;height: 200px;background:red;position: absolute;left: 600px;top:0;border-radius:50%;
        }
        .ul{position: absolute;left: 100px;top: 300px;}
        .ul li{float: left;margin-right: 10px;color: #FFF;cursor: pointer;}
        #left{width: 40px;height: 40px;background:#000000;}
        #right{width: 40px;height: 40px;background:#000000;}
    </style>
</head>
<body>
<div id="div1"></div>
<ul class="ul">
    <li id="left">左</li>
    <li id="right">右</li>
</ul>
</body>
</html>
<script>
    var oDiv=document.getElementById("div1");
    var oLeft=document.getElementById("left");
    var oRight=document.getElementById("right");
    var timer=null;//全局变量;
    oLeft.onclick=function(){move(oDiv,0)};
    //点完left后,move运行,还要开启一个定时器;等30ms;timer=function(){move(ele,target)},在等待时候,15ms点了一下右,move方法再去执行;会清除timer;
    oRight.onclick=function(){move(oDiv,800)};
    function move(ele,target){
        clearTimeout(timer);
        var cur=getCss(ele,"left");
        if(cur<target){//当前位置小于目标值;
            if(cur+11>=target){//临界值的判断;
                ele.style.left=target+"px";
            }else{
                ele.style.left=getCss(ele,"left")+11+"px";
            }
            timer=window.setTimeout(function(){move(ele,target)},30)
        }else if(cur>target){//当前位置大于目标值
            if(cur-11<=target){
                ele.style.left=target+"px";
            }else{
                ele.style.left=getCss(ele,"left")-11+"px";
            }
            timer=window.setTimeout(function(){move(ele,target)},30)
        }
    };
    function getCss(ele,attr){
        //变量未定义不能直接用,如果相判断一个变量是否存在可以typeof;
        //属性未定义可以直接使用;
        if(typeof getComputedStyle){
            return parseFloat(getComputedStyle(ele,null)[attr]);
        }else{
            return parseFloat(attr.currentStyle[attr]);
        }
    };

</script>

代码3

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>从右向左运动</title>
    <style>
        ul,li{list-style: none;}
        #div1{
            width: 200px;height: 200px;background:red;position: absolute;left: 600px;top:0;border-radius:50%;
        }
        .ul{position: absolute;left: 100px;top: 300px;}
        .ul li{float: left;margin-right: 10px;color: #FFF;cursor: pointer;}
        #left{width: 40px;height: 40px;background:#000000;}
        #right{width: 40px;height: 40px;background:#000000;}
    </style>
</head>
<body>
<div id="div1"></div>
<ul class="ul">
    <li id="left">左</li>
    <li id="right">右</li>
</ul>
</body>
</html>
<script>
    var oDiv=document.getElementById("div1"),
            oLeft=document.getElementById("left"),
            oRight=document.getElementById("right");
    /*确定左右的终点*/
    var cW = document.documentElement.clientWidth || document.body.clientWidth;
    var tarR = cW - oDiv.offsetWidth,
            tarL = 0;

    oLeft.onclick=function(){
        move(oDiv,tarL);
    };
    oRight.onclick=function(){
        move(oDiv,tarR);
    };

    var timer=null;//全局变量;
    function move(oDiv,target) {
        var start = getCss(oDiv,"left"),
                count = start;
        _move();
        function _move() {
            clearTimeout(oDiv.timer);
            if (start < target) {//右
                if (count + 10 >= target) {
                    setCss(oDiv, "left", target);
                    return;
                }
                count += 10;
                setCss(oDiv, "left", count);
            } else if (start > target) {//左
                if (count - 10 <= target) {
                    setCss(oDiv, "left", target);
                    return;
                }
                count -= 10;
                setCss(oDiv, "left", count);
            } else {
                return;
            }
            oDiv.timer = setTimeout(_move, 10);
        }
    }
    function getCss(curEle,attr) {
        var reg = /^(?:margin|padding|border|float|position|display|background|backgroundColor)$/;
        var flag="getElementsByClassName" in document;
        var value = flag ? window.getComputedStyle(curEle, null)[attr] : curEle.currentStyle[attr];
        return !reg.test(attr) ? parseFloat(value) : value;
    }
    function setCss(curEle,attr,value) {
        if(typeof value!=="undefined"){
            switch (attr) {
                case "opacity":
                    curEle["style"][attr] = value;
                    curEle["style"]["filter"] = "alpha(opacity=" + (value * 100) + ")";
                    break;
                case "zIndex":
                    curEle["style"][attr] = value;
                    break;
                default:
                    curEle["style"][attr] = !isNaN(value) ? value += "px" : value;
            }
        }
    };
</script>

代码4

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>从右向左运动</title>
    <style>
        ul,li{list-style: none;}
        #div1{
            width: 200px;height: 200px;background:red;position: absolute;left: 600px;top:0;border-radius:50%;
        }
        .ul{position: absolute;left: 100px;top: 300px;}
        .ul li{float: left;margin-right: 10px;color: #FFF;cursor: pointer;}
        #left{width: 40px;height: 40px;background:#000000;}
        #right{width: 40px;height: 40px;background:#000000;}
    </style>
</head>
<body>
<div id="div1"></div>
<ul class="ul">
    <li id="left">左</li>
    <li id="right">右</li>
</ul>
</body>
</html>
<script>
    var oDiv=document.getElementById("div1"),
            oLeft=document.getElementById("left"),
            oRight=document.getElementById("right");
    /*确定左右的终点*/
    var cW = document.documentElement.clientWidth || document.body.clientWidth;
    var tarR = cW - oDiv.offsetWidth,
            tarL = 0;

    oLeft.onclick=function(){
        move(oDiv,tarL);
    };
    oRight.onclick=function(){
        move(oDiv,tarR);
    };

    var timer=null;//全局变量;
    function move(oDiv,target) {
        var start = setCss(oDiv,"left"),
                count = start;
        _move();
        function _move() {
            clearTimeout(oDiv.timer);
            if (start < target) {//右
                if (count + 10 >= target) {
                    setCss(oDiv, "left", target);
                    return;
                }
                count += 10;
                setCss(oDiv, "left", count);
            } else if (start > target) {//左
                if (count - 10 <= target) {
                    setCss(oDiv, "left", target);
                    return;
                }
                count -= 10;
                setCss(oDiv, "left", count);
            } else {
                return;
            }
            oDiv.timer = setTimeout(_move, 10);
        }
    }
    function setCss(curEle,attr,value) {//设置CSS属性值和获取CSS;如果三个参数就是设置,2个参数就是获取;att是attribute的缩写;
        if(typeof value==="undefined"){//如果有第三个参数,就是设置Css;如果没有就是获取Css;
            var reg = /^(?:margin|padding|border|float|position|display|background|backgroundColor)$/;
            var flag="getElementsByClassName" in document;
            var value = flag ? window.getComputedStyle(curEle, null)[attr] : curEle.currentStyle[attr];
            return !reg.test(attr) ? parseFloat(value) : value;
        } else{
            switch (attr) {
                case "opacity":
                    curEle["style"][attr] = value;
                    curEle["style"]["filter"] = "alpha(opacity=" + (value * 100) + ")";
                    break;
                case "zIndex":
                    curEle["style"][attr] = value;
                    break;
                default:
                    curEle["style"][attr] = !isNaN(value) ? value += "px" : value;
            }
        }
    };
</script>

AXIHE / 精选资源

浏览全部教程

面试题

学习网站

前端培训
自己甄别

前端书籍

关于朱安邦

我叫 朱安邦,阿西河的站长,在杭州。

以前是一名平面设计师,后来开始接接触前端开发,主要研究前端技术中的JS方向。

业余时间我喜欢分享和交流自己的技术,欢迎大家关注我的 Bilibili

关注我: Github / 知乎

于2021年离开前端领域,目前重心放在研究区块链上面了

我叫朱安邦,阿西河的站长

目前在杭州从事区块链周边的开发工作,机械专业,以前从事平面设计工作。

2014年底脱产在老家自学6个月的前端技术,自学期间几乎从未出过家门,最终找到了满意的前端工作。更多>

于2021年离开前端领域,目前从事区块链方面工作了