zoukankan      html  css  js  c++  java
  • JS运动

    JS运动对元素样式操作,

    运动基础:

    如何让div运动起来?

    如下:
    1.设置元素为决定定位,只有绝对对位后,left,top等值生效
    2.定时器的使用(动态改变值),这里使用setInterval()每隔一段时间执行代码
    setInterval(函数,交互时间);
    clearInterval(定时器名),
    3.获取当前位置、大小等等。offsetLeft(当前元素相对父元素偏执)
    4.速度--物体运动的快慢

    根据上面的代码实现简单的运动

        var box=document.getElementById("box");
        function startMove(curEle){
            timer=setInterval(function(){
                curEle.style.left=curEle.offsetLeft+5+"px";
            },30)
        }
        startMove(box)

    上面的这个动画不会停止,ok,我们设置一个停止条件

      var box=document.getElementById("box");
        var timer=null;
        function startMove(curEle,target){
            timer=setInterval(function(){
                if (curEle.offsetLeft===target){
                    clearInterval(timer);
                    return;
                }
                curEle.style.left=curEle.offsetLeft+5+"px";
            },30)
        }
        startMove(box,800)
    我们发现一个BUG,个别值不会触发停止条件
    BUG:
    1.运动到某些值无法停止
    2.重复点击会加快速度
    3.速度无法改变
    解决:
    1.一会搞
    2.每次点击清除定时器
    3.把速度以变量保存
        var box=document.getElementById("box");
        var timer=null;
        function startMove(curEle,target){
            clearInterval(timer)
            timer=setInterval(function(){
                var speed=5;
                if (curEle.offsetLeft===target){
                    clearInterval(timer);
                    return;
                }
                curEle.style.left=curEle.offsetLeft+speed+"px";
            },30)
        }
        btnLeft.onclick=function(){startMove(box,800)}
    等一下,方向为什么不能变:我现在想向左走了
        var box=document.getElementById("box");
        var timer=null;
        function startMove(curEle,target){
            clearInterval(timer);
            var curPos=curEle.offsetLeft;
            //        判断当前值与目标值谁大谁小
            var speed=curPos>target?-7:7;
            timer=setInterval(function(){
                var curLeft=curEle.offsetLeft;
    //            先加速度,计算后的值进行判断
                curLeft+=speed;
                if (speed>0&&curLeft>=target){
                    curEle.style.left=target+"px";
                    clearInterval(timer);
                    return;
                }else if(speed<0&&curLeft<=target){
                    curEle.style.left=target+"px";
                    clearInterval(timer);
                    return;
                }
                curEle.style.left=curLeft+"px";
            },30)
        }
        btnLeft.onclick=function(){startMove(box,document.documentElement.clientWidth-box.offsetWidth)}
    如果是透明度,我们怎么办,需要特殊判断

    补充的两个方法

    getcss获取样式

       function getCss(curEle,attr){
            var val=null;
            if (!/MSIE (6|7|8)/.test(window.navigator.userAgent)){
                val=window.getComputedStyle(curEle,null)[attr]
            }else{
                if (attr==="opacity"){
                    val=curEle.currentStyle["filter"];
                    var reg=/^alpha(opacity=(d+(?:.d+)?))/
                    val=reg.exec(val)?reg.exec(val)[1]/100:1;
                }else{
                    val=curEle.currentStyle[attr];
                }
            }
    //        去单位
            var reg=/^(-?d+(.d+)?)(px|pt|rem|em)$/;
            return reg.test(val)?parseFloat(val):val;
        }

    setcss设置样式

        function setCss(curEle,attr,value){
            if (attr==="opacity"){
                curEle["style"]["opacity"]=value;
                curEle["style"]["filter"]="alpha(opacity="+value*100+")";
                return
            }
            if (attr==="float"){
                curEle["style"]["cssFloat"]=value;
                curEle["style"]["styleFloat"]=value;
                return
            }
            var reg=/^(width|height|left|top|bottom|right|((maring|padding)|(Left|Right|Top|Bottom)?))$/i;
            if (reg.test(attr)){
                if (!isNaN(value)){
                    value+="px";
                }
            }
            curEle["style"][attr]=value;
        }

    思路一:步长法

       var duration=2000,interval=10,target=600,change=target-getCss(box,"left");
        var step=change/duration*interval;
        var timer=setInterval(function(){
            var curLeft=getCss(box,"left");
            curLeft+=step;
            if (curLeft>target){
                setCss(box,target)
                clearInterval(timer);
                return
            }
            curLeft+=step;
            setCss(box,"left",curLeft)
        },interval)

    思路二、

        function Linear(t,d,c,b){
            return t/d*c+b
        }
    
        var duration=2000,time= 0,begin=getCss(box,"left"),target=1200;
        var change=target-begin;
        var timer=setInterval(function(){
            time+=10;
            var pos=Linear(time,duration,change,begin);
            console.log(pos)
            if (time>duration){
                setCss(box,target)
                clearInterval(timer)
                return
            }
            setCss(box,"left",pos)
        },10)

    思路三:使用setTimeout实现定时器

    //使用递归思想实现   
    var timer=null; function move(){ // 每一次执行,清空定时器 clearTimeout(timer); var duration=2000,interval=10,target=600,change=target-getCss(box,"left"); var step=change/duration*interval; var curLeft=getCss(box,"left"); curLeft+=step;
    // 当前left+step大于target时;直接让left=target
    if (curLeft>target){ setCss(box,"left",curLeft); clearTimeout(timer); return } setCss(box,"left",curLeft); timer=setTimeout(move,interval) } move();

    进化:可以用按钮控制方向

        function move(target){
            _move()    //此处为什么+小_move,看定时器
            function _move(){
                clearTimeout(box.timer)
                var duration=2000,interval=10;
                var curLeft=getCss(box,"left");
                if (target>curLeft){
                    curLeft+=5;
                    if (curLeft>target){
                        curLeft=target;
                        clearTimeout(box.timer)
                    }
    
                }else if(target<curLeft){
                    curLeft-=5;
                    if (target>curLeft){
                        curLeft=target;
                        clearTimeout(box.timer)
                    }
                }
                setCss(box,"left",curLeft);
                box.timer=window.setTimeout(_move,interval)  //定时器之前因为move有参数,所以要先执行个匿名函数,再匿名函数中执行move(target),每次递归都会创建一个多余的作用域,浪费资源
            }
        }
        btL.onclick=function(){
            var target=0;
            move(target);
        }
        btR.onclick=function(){
            var target=(document.documentElement.clientWidth||document.body.clientWidth)-getCss(box,"width");
            move(target)
    
        }

    同元素多样式运动


    function linear(t,d,b,c){ return t/d*c+b; } function move(curEle,target,duration,callback){
    //先计算出,初始值与距离存在两个变量里
    var begin={},change={}; duration=duration||2000; for(var key in target){ if (target.hasOwnProperty(key)){ begin[key]=utils.css(curEle,key); change[key]=target[key]-begin[key]; } }
    var time=0; curEle.timer=setInterval(function(){ time+=10; for(var key in target){ if (target.hasOwnProperty(key)){
    //当time 时间超过了总时间停止运动
    if (time>duration){ utils.css(curEle,key,target[key]); clearInterval(curEle.timer);
    //停止运动时执行回调函数 callback
    &&callback() return; } var curPos=linear(time,duration,begin[key],change[key]); utils.css(curEle,key,curPos) } } },30) } move(box,{ left:"100", top:"100", opacity:"1" },200,function(){ console.log("动画执行完了") })

    万能动画框架 

    //以下是动画的算法
    var zhufengEffect = {
        //当前时间*变化量/持续时间+初始值
        zfLinear: function(t,b,c,d){ return c*t/d + b; },
        Quad: {//二次方的缓动(t^2);
            easeIn: function(t,b,c,d){
                return c*(t/=d)*t + b;
            },
            easeOut: function(t,b,c,d){
                return -c *(t/=d)*(t-2) + b;
            },
            easeInOut: function(t,b,c,d){
                if ((t/=d/2) < 1) return c/2*t*t + b;
                return -c/2 * ((--t)*(t-2) - 1) + b;
            }
        },
        Cubic: {//三次方的缓动(t^3)
            easeIn: function(t,b,c,d){
                return c*(t/=d)*t*t + b;
            },
            easeOut: function(t,b,c,d){
                return c*((t=t/d-1)*t*t + 1) + b;
            },
            easeInOut: function(t,b,c,d){
                if ((t/=d/2) < 1) return c/2*t*t*t + b;
                return c/2*((t-=2)*t*t + 2) + b;
            }
        },
        Quart: {//四次方的缓动(t^4);
            easeIn: function(t,b,c,d){
                return c*(t/=d)*t*t*t + b;
            },
            easeOut: function(t,b,c,d){
                return -c * ((t=t/d-1)*t*t*t - 1) + b;
            },
            easeInOut: function(t,b,c,d){
                if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
                return -c/2 * ((t-=2)*t*t*t - 2) + b;
            }
        },
        Quint: {//5次方的缓动(t^5);
            easeIn: function(t,b,c,d){
                return c*(t/=d)*t*t*t*t + b;
            },
            easeOut: function(t,b,c,d){
                return c*((t=t/d-1)*t*t*t*t + 1) + b;
            },
            easeInOut: function(t,b,c,d){
                if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
                return c/2*((t-=2)*t*t*t*t + 2) + b;
            }
        },
        Sine: {//正弦曲线的缓动(sin(t))
            easeIn: function(t,b,c,d){
                return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
            },
            easeOut: function(t,b,c,d){
                return c * Math.sin(t/d * (Math.PI/2)) + b;
            },
            easeInOut: function(t,b,c,d){
                return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
            }
        },
        Expo: {//指数曲线的缓动(2^t);
            easeIn: function(t,b,c,d){
                return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
            },
            easeOut: function(t,b,c,d){
                return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
            },
            easeInOut: function(t,b,c,d){
                if (t==0) return b;
                if (t==d) return b+c;
                if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
                return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
            }
        },
        Circ: {//圆形曲线的缓动(sqrt(1-t^2));
            easeIn: function(t,b,c,d){
                return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
            },
            easeOut: function(t,b,c,d){
                return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
            },
            easeInOut: function(t,b,c,d){
                if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
                return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
            }
        },
        Elastic: {//指数衰减的正弦曲线缓动;
            easeIn: function(t,b,c,d,a,p){
                if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
                if (!a || a < Math.abs(c)) { a=c; var s=p/4; }
                else var s = p/(2*Math.PI) * Math.asin (c/a);
                return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
            },
            easeOut: function(t,b,c,d,a,p){
                if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
                if (!a || a < Math.abs(c)) { a=c; var s=p/4; }
                else var s = p/(2*Math.PI) * Math.asin (c/a);
                return (a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b);
            },
            easeInOut: function(t,b,c,d,a,p){
                if (t==0) return b;  if ((t/=d/2)==2) return b+c;  if (!p) p=d*(.3*1.5);
                if (!a || a < Math.abs(c)) { a=c; var s=p/4; }
                else var s = p/(2*Math.PI) * Math.asin (c/a);
                if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
                return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
            }
        },
        Back: {//超过范围的三次方缓动((s+1)*t^3 - s*t^2);
            easeIn: function(t,b,c,d,s){
                if (s == undefined) s = 1.70158;
                return c*(t/=d)*t*((s+1)*t - s) + b;
            },
            easeOut: function(t,b,c,d,s){
                if (s == undefined) s = 1.70158;
                return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
            },
            easeInOut: function(t,b,c,d,s){
                if (s == undefined) s = 1.70158; 
                if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
                return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
            }
        },
        zfBounce: {//指数衰减的反弹缓动。
            easeIn: function(t,b,c,d){
                return c - zhufengEffect.zfBounce.easeOut(d-t, 0, c, d) + b;
            },
            easeOut: function(t,b,c,d){
                if ((t/=d) < (1/2.75)) {
                    return c*(7.5625*t*t) + b;
                } else if (t < (2/2.75)) {
                    return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
                } else if (t < (2.5/2.75)) {
                    return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
                } else {
                    return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
                }
            },
            easeInOut: function(t,b,c,d){
                if (t < d/2) return zhufengEffect.zfBounce.easeIn(t*2, 0, c, d) * .5 + b;
                else return zhufengEffect.zfBounce.easeOut(t*2-d, 0, c, d) * .5 + c*.5 + b;
            }
        }
    }
    ////////////////////以上都是算法
    /*
        animate的参数:当effect参数是数字的情况
        effect:是指定的动画效果,它可以由一个简单数字来快捷表示某种常用的动画效果,也可以以数组的方式来指定某个不常用的动画效果。还可以不给effect参数传值,则动画使用默认的效果(我们指定减速的效果为默认效果)
        如果用数字来快捷表示某种常用效果效,则
        0:减速效果Expo
        1:匀速效果:linear
        2:弹性:Elastic
        3:返回:Back
        4:反弹:Bounce
    
    */
    
    /*
        effect参数的第二情况:当它是一个数组的情况
    animate(ele,{left:600},1500,['zfBounce','easeInOut'],callback)
    
    zhufengEffect.zfBounce.easeInOut
    zhufengEffect["zfBounce"]["easeInOut"];
    var a=['zfBounce','easeInOut'];
    zhufengEffect[a[0]][a[1]];//要明白这一行和161,162是一样的
    
    */
    /*
    animate(ele,{left:600},1500,callback)
    当第四个参数是function的时候(按理说第五个参数才应该是回调函数呢,现在由于第四个参数没有传,但是回调函数传进来了,则会出现回调函数成为第四个参数的可能)
        现在则需要把这个方法当成回调方法来执行。在这种情况下,则认为没指定动画效果,而是把第四个参数按成第五个参数:回调方法去执行
    
    */
    
    /*
    
    方法重载和方法重写,是面向对象的“多态”中的概念。面向对象有三大基本特征:封装、继承、多态(一个方法有多种形态,方法重载)
    JS中是不支持方法重载的,但是可以使用判断参数的类型或参数个数来模拟实现方法重载
    我们的animate方法就是这样
    
    方法重写是指写义在子类上的方法覆盖了父类上的方法,比如Array.prototype.toString覆盖了Object.prototype.toString,在Array类的实例上再使用toString方法,就访问不到Object类上的toString方法了
    */
    function animate(ele,obj,duration,effect,callback){
        var fnEffect=zhufengEffect.Expo.easeOut;
        
        if(typeof effect == "number"){
            switch(effect){
                case 0:
                    break;
                case 1:
                    fnEffect=zhufengEffect.zfLinear;
                    break;
                case 2:
                    fnEffect=zhufengEffect.Elastic.easeOut;
                    break;
                case 3:
                    fnEffect=zhufengEffect.Back.easeOut;
                    break;
                case 4:
                    fnEffect=zhufengEffect.zfBounce.easeOut;
                    break;    
                
                
            }
        }else if(effect instanceof Array){
            if(effect.length==2)
                fnEffect=zhufengEffect[effect[0]][effect[1]];
        }else if(typeof effect =="function"){
            callback=effect;    
        }
        
        
        var oBegin={};//用来保存多个方向begin;
        var oChange={};//用来保存多个方向的change;
        
        var flag=0;//用来记录各个方向的距离是否有效
        for(var attr in obj){
            var target=obj[attr]
            var begin=animate.getCss(ele,attr);
            var change=target-begin;
            
            if(change){//判断一下此方向的运动距离有效,不为0        
                oBegin[attr]=begin;
                oChange[attr]=change;
                flag++;
            }
        }//for in 循环结束
        if(!flag)return;//如果各个方向的运动距离都是0,则结束动画的执行
        var interval=15;
        var times=0;
        
        clearInterval(ele.timer);
        
        function step(){
            
            times+=interval;
            if(times<duration){
                for(var attr in oChange){
                    var change=oChange[attr];
                    var begin=oBegin[attr];
                    //var val=times/duration*change+begin;
                    var val=fnEffect(times,begin,change,duration);
                    animate.setCss(ele,attr,val);
                }
            }else{
                for(var attr in oChange){
                    var target=obj[attr];
                    animate.setCss(ele,attr,target);    
                }
                clearInterval(ele.timer);
                ele.timer=null;
                if(typeof callback == "function"){
                    callback.call(ele);    
                }
            }
            
        }
        ele.timer=setInterval(step,interval);
    };
    
    animate.getCss=function(ele,attr){
        if(window.getComputedStyle){
            return parseFloat(window.getComputedStyle(ele,null)[attr]);    
        }else{
            if(attr=="opacity"){
                var val=ele.currentStyle.filter;
                //"alpha(opacity=50)";//匹配到这样的一个字符串,然后把这个字符串中的数字部分拿到
                var reg=/alpha(opacity=(d+(?:.d+)?))/;
                if(reg.test(val)){
                    return RegExp.$1/100;
                }else{
                    //如果没有给IE中的不透明度赋值,则上边的正则为false
                    return 1;//如果没有给不透明度赋值,则应该把默认值1返回
                }
                //方法没有返回值,则此方法执行结束后留下一个undefined。即:没有返回值的方法返回的是undefined
            }else{
                return parseFloat(ele.currentStyle[attr]);
            }        
        }
    }
    
    animate.setCss=function(ele,attr,val){
            if(attr=="opacity"){
                ele.style.opacity=val;
                ele.style.filter="alpha(opacity="+val*100+")";
            }else{
                ele.style[attr]=val+"px";
            }
    }
  • 相关阅读:
    EXPDP fails with ORA-39126 Worker unexpected fatal error in KUPW$WORKER.FETCH_XML_OBJECTS (Doc ID 2656308.1)
    github+maven+jenkins(spring boot项目自动化发布)
    Compose部署Fabric-explorer
    Compose部署IPFS星际文件系统以及sdk的使用
    Git常用命令以及常见问题解决
    Chrome 卡顿优化
    The "Go" Learning Trip -- 2. Go Basics -- Part2
    The "Go" Learning Trip -- 1. Hello Go, Frist “go” Code -- Part1
    Go语言 踩坑录(报错锦集)
    WEB开发基础(CSS篇)
  • 原文地址:https://www.cnblogs.com/liangfc/p/8808001.html
Copyright © 2011-2022 走看看