【javascript】运动与游戏开发

本文深入讲解JavaScript中的运动框架,包括运动的基本概念、定时器的使用、常见运动类型如匀速和变速运动,以及多物体运动、链式运动等高级技巧。并通过具体案例,如banner轮播图、打砖块游戏等展示运动框架的实际应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、学习运动框架作用

  • web页面开发的过程中,如何与用户进行友好、有趣的交互,是我们必须考虑的问题。 比如:
    1. 导航条中滑动的动画特效
    2. 点击加入购物车按钮通过抛物线
    3. 加入右侧购物车的动画特效
    4. 网页游戏的开发:微信打飞机、打砖块等

二、运动原理

  • Js运动:
    就是让 web 上 DOM 元素动起来改变其自身的位置属性,比如高宽,左边距,上边距,透明度等。
    动画的原理就是把不同状态的物体,串成连续的样子。
    js动画也一样,不同状态的DOM用定时器控制,就能得到动画效果。
  • 人眼能够识别的最小的时间间隔是18帧。
    【注】电影院电影24帧。
  • 如何实现运动:
    1.运动的物体使用绝对定位
    2.通过改变定位物体的属性(left、right、top、bottom)值来使物体移动。例如
    向右或左移动可以使用offsetLeft(offsetRight)来控制左右移动。
  • 步骤:
    1. 开始运动前,先清除已有定时器 (因为:是连续点击按钮,物体会运动越来越快,造成运动混乱)
    2. 开启定时器,计算速度
    3. 把运动和停止隔开(if/else),判断停止条件,执行运动

三、定时器

  • 在javascritp中,有两个关于定时器的专用函数,它们是倒计定时器、循环定时器。

3.1. 倒计定时器:timer=setTimeout(函数名,delaytime);

  • 倒计时定时器就是在指定时间后触发事件,只是作用一次
  • 一般用于页面上只需要触发一次的的情况,比如点击某按钮后页面在一定时间后跳转到相应的站点,也可以用于判断一个浏览者是不是你的站点上的“老客”,如果不是,你就可以在5秒或者10秒后跳转到相应的站点,然后告诉他以后再来可以在某个地方按某一个按钮就可以快速进入。

3.2. 循环定时器:timer=setInterval(函数名,delaytime);

  • 循环定时器就是在间隔时间到来时反复触发事件,不停地作用。

  • 一般用于站点上需要从复执行的效果,比如一个javascript的滚动条或者状态栏,也可以用于将页面的背景用飞雪的图片来表示。这些事件需要隔一段时间运行一次。

  • function()是定时器触发时要执行的是事件的函数,可以是一个函数,也可以是几个函数,或者javascript的语句也可以,单要用;隔开;

  • delaytime则是间隔的时间,以毫秒为单位

3.3 删除定时器 clearTimeout(timename) clearInterval(timename)

  • clearTimeout(timename)关闭倒计时定时器
  • clearInterval(timename)来关闭循环定时器

四、运动研究

4.1. 运动:匀速运动(让物体动起来)

  1. 对定时器的使用
  2. 给DIV加绝对定位
  3. offsetLeft
  • 【例】分享到菜单:
window.onload = function(){
    var oMenu = document.getElementById("menu");
    oMenu.onmouseenter = function(){
        //-100 => 0
        startMove(0);
    }
    oMenu.onmouseleave = function(){
        //0 => -100
        startMove(-100);
    }
    var timer = null;
    function startMove(iTarget){
        var oMenu = document.getElementById("menu");
        var speed = 10;
        //1、每次启动定时器将上一次定时器关闭
        clearInterval(timer);
        timer = setInterval(function(){
            if(oMenu.offsetLeft < iTarget){
                speed = Math.abs(speed);
            }else{
                speed = -Math.abs(speed);
            }

            //2、运动和停止分开
            if(oMenu.offsetLeft == iTarget){
                clearInterval(timer);
            }else{
                oMenu.style.left = oMenu.offsetLeft + speed + 'px';
            }
        }, 30);
    }
}
  • 【例】 淡入淡出
window.onload = function(){
    var oImg = document.getElementById("img1");
    oImg.onmouseenter = function(){
        //30 => 100
        startMove(100);
    }
    oImg.onmouseleave = function(){
        //100 => 30
        startMove(30);
    }
    /* 
        类似于透明度这类型的css属性,使用中间变量替代计算。
     */
    var alpha = 30;
    var timer = null;
    function startMove(iTarget){
        var oImg = document.getElementById("img1");
        var speed = 2;
        clearInterval(timer);
        timer = setInterval(function(){
            if(alpha > iTarget){
                speed = -Math.abs(speed);
            }else{
                speed = Math.abs(speed);
            }
            //1、取当前值
            if(alpha == iTarget){
                clearInterval(timer);
            }else{
                alpha += speed;
                //給当前图片上设置透明度,考虑浏览器兼容
                oImg.style.opacity = alpha / 100;
                oImg.style.filter = "alpha(opacity=" + alpha + ")";
                document.title = alpha;
            }
        }, 30);
    }
}
  1. 问题:到达某个特定位罝停止
    解决:做判断,符合条件时关掉定时器(存定时器timer)
      速度变慢(一般不动时间,而是改数字-速度)
      用变量存速度

  2. 问题:取7时,offsetLeft没有等于300的时候,div停不下来
    解决:>=300 //停在 301

  3. 问题:到300后点击按钮还继续走
    原因:点击按钮,执行函数,开定时器(执行当前函数一至少执行一次)
    解决:加else (没有到达目标之前才执行)

  4. 问题:连续点击,速度变快
    原因:每点击一次就开一个定时器,点击几次就有几个定时器同时工作
    解决:保证每次只有一个定时器工作,先cearlnterval ()

4.2、变速运动

逐渐变慢,最后停止
距离越远速度越大
速度由距离决定
速度=(目标值-当前值)/缩放系数

  • 【例】缓冲运动
    var speed = 距离;
    var speed = (iTarget - iCur) / 8;
    速度:0.375 计算机最小能够识别的像素是一像素。
window.onload = function(){
     var oBtn = document.getElementById("btn1");
     var oDiv = document.getElementById("div1");
     oBtn.onclick = function(){
         startMove(500);
     }
     var timer = null;
     function startMove(iTarget){
         var oDiv = document.getElementById("div1");
         var oTxt1 = document.getElementById("txt1");
         clearInterval(timer);
         timer = setInterval(function(){
              //计算速度
             var speed = (iTarget - oDiv.offsetLeft) / 8;
             speed = Math.ceil(speed);
             if(oDiv.offsetLeft == iTarget){
                 clearInterval(timer);
             }else{
                 oDiv.style.left = oDiv.offsetLeft + speed + 'px';
                 txt1.value += oDiv.offsetLeft + ", " + speed + "\n";
             }
         }, 30);
     }
 }
  • 【缓存菜单】
window.onload = function(){
    var oMenu = document.getElementById("menu");
    //获取当前的目的值
    var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
    var windowHeight = document.documentElement.clientHeight || document.body.clientHeight;
    var iH = parseInt(scrollTop + (windowHeight - oMenu.offsetHeight) / 2);
    startMove(iH);
    window.onscroll = function(){
        var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
        var windowHeight = document.documentElement.clientHeight || document.body.clientHeight;
        var iH = parseInt(scrollTop + (windowHeight - oMenu.offsetHeight) / 2);

        startMove(iH);
    }
}

var timer = null;
function startMove(iTarget){
    var oMenu = document.getElementById("menu");
    clearInterval(timer);
    timer = setInterval(function(){
        //计算速度
      

 var speed = (iTarget - oMenu.offsetTop) / 8;
                  speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);

                  //运动和停止分开
                  if(oMenu.offsetTop == iTarget){
                      clearInterval(timer);
                  }else{
                      oMenu.style.top = oMenu.offsetTop + speed + 'px';
                      document.title = oMenu.offsetTop + ", " + iTarget;
                  }

              }, 30);
          }

如果没有【缩放系数】速度太大,瞬间到达终点.没有过程

  1. 问题:并没有真正到达300
    原因:速度只剩0.9 像素是屏幕能够显示的最小单位,并不会四舍五入掉

    • Math.ceil() 向上取整
    • Math.floor() 向下取整
  2. 问题:向左走,又差一块–Math.floor ()
    判断:三目 speed=speed>0 ? Math.ceil ( speed ): Math.floor ( speed )
    示例代码:

4.3、多物体运动

多个div ,鼠标移入变宽
运动框架传参obj,知道让哪个物体动起来
用到缓冲一定要取整
*【多物体运动】

window.onload = function(){
    var aDivs = document.getElementsByTagName("div");
    for(var i = 0; i < aDivs.length; i++){
        aDivs[i].onmouseover = function(){
            startMove(this, 300);
        }
        aDivs[i].onmouseout = function(){
            startMove(this, 100);
        }
    }
}

/* 
    原因是:我们整个页面上只有一个定时器。
    解决:让每一个运动的物体,独立拥有自己的定时器。

*/
// var timer = null;

function startMove(node, iTarget){
    clearInterval(node.timer);
    node.timer = setInterval(function(){
        //确定缓冲运动的速度
        var speed = (iTarget - node.offsetWidth) / 8;
        speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);

        if(node.offsetWidth == iTarget){
            clearInterval(node.timer);
        }else{
            node.style.width = node.offsetWidth + speed + 'px';
        }

    }, 30);
}
  • 【多物体-淡入淡出】
window.onload = function(){
   var aDivs = document.getElementsByTagName("div");
   for(var i = 0; i < aDivs.length; i++){
       aDivs[i].alpha = 30;
       aDivs[i].onmouseover = function(){
           startMove(this, 100);
       }
       aDivs[i].onmouseout = function(){
           startMove(this, 30);
       }
   }
}


/* 
   中间变量:多个物体在进行透明度变化的时候,公用的是一个中间变量。

   结论:任何的变量在多物体运动中,都不能共用。
*/
// var alpha = 30;

function startMove(node, iTarget){
  clearInterval(node.timer);
  node.timer = setInterval(function(){
      var speed = (iTarget - node.alpha) / 8;
      speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);

      if(node.alpha == iTarget){
          clearInterval(node.timer);
      }else{
          node.alpha += speed;

          node.style.opacity = node.alpha / 100;
          node.style.filter = "alpha(opacity=" + node.alpha + ")";
      }

  }, 30);
}
  1. 问题:div没运动回去 //清除前一个定时器
    原因:只有一个定时器
    解决:加物体上的定时器,使每个物体都有一个定时器。定时器作为物体属性
    多个div淡入淡出
    首先关闭物体上的定时器
    经验:多物体运动框架所有东西都不能共用

  2. 问题:不是因为定时器,而是因为alpha
    解决:作为属性附加到物体上 /不以变量形式存在

  3. 问题:offset 的 bug 加border变宽
    原因:offsetWith并不是真正的width ,它获取的是盒模型尺寸
    解决:躲着 宽度扔到行间,parselnt ( oDiv.style.width )
    进一步解决: getStyle ( obj, name ) currentStyle , getComputedStyle
    加border ,只要offset就有问题 去掉offset
    示例,多物体运动框架:

4.4.任意值运动

  • 【offset问题】
 window.onload = function(){
     var oDiv = document.getElementById("div1");
     setInterval(function(){
         // alert(oDiv.offsetWidth); //width + border
         oDiv.style.width = oDiv.offsetWidth - 1 + 'px';
     }, 30);
 }
  • 用getStyle方法来获取当前有效样式
    node.currentStyle ? node.currentStyle[cssStr] : getComputedStyle(node)[cssStr];
window.onload = function(){
  var oDiv = document.getElementById("div1");
  setInterval(function(){
      //获取当前值
      var iCur = parseInt(getStyle(oDiv, "width"));
      alert(iCur);
      oDiv.style.width = iCur - 1 + 'px';
  }, 30);
}
//获取当前有效样式浏览器兼容的写法
function getStyle(node, cssStr){
  return node.currentStyle ? node.currentStyle[cssStr] : getComputedStyle(node)[cssStr];
}
  • 任意值运动的单位分为透明度和px。
  • px单位的任意值
  • 【多物体多样式】
window.onload = function(){
    var aDivs = document.getElementsByTagName("div");
    aDivs[0].onclick = function(){
        //宽变成300
        startMove(this, "width", 300);
    }

    aDivs[1].onclick = function(){
        //高变成300
        startMove(this, "height", 300);
    }

    aDivs[2].onclick = function(){
        //marginLeft => 300
        startMove(this, "marginLeft", 300);
    }

    aDivs[3].onclick = function(){
        //fontSize => 100
        startMove(this, "fontSize", 100);
    }

    aDivs[4].onmouseover = function(){
        startMove(this, "opacity", 100);
    }
    aDivs[4].onmouseout = function(){
        startMove(this, "opacity", 30);
    }
}

//startMove(oDiv, "width", 300);
function startMove(node, attr, iTarget){
    clearInterval(node.timer);
    node.timer = setInterval(function(){
        //计算速度
        var iCur = null;
        if(attr == "opacity"){
            iCur = parseInt(parseFloat(getStyle(node, "opacity")) * 100);
        }else{
            iCur = parseInt(getStyle(node, attr))
        }
        
        var speed = (iTarget - iCur) / 8;
        speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);

        if(iCur == iTarget){
            clearInterval(node.timer);
        }else{
            if(attr == "opacity"){
                iCur += speed;
                node.style.opacity = iCur / 100;
                node.style.filter = "alpha(opacity=" + iCur +  ")";
            }else{
                node.style[attr] = iCur + speed + 'px';
            }
        }
    }, 30);
}

4.5.链式运动

  • 链式运动
    • 在第一个动画结束的时候,开始第二个动画。
    • 【注】关键点,找到第一个动画结束的时候。
window.onload = function(){
    var aDivs = document.getElementsByTagName("div");
aDivs[0].onmouseover = function(){
 //嵌套function 实现链式运动
      startMove(this, "width", 300, function(){
          startMove(this, "height", 300, function(){
              startMove(this, "opacity", 100);
          })
      });     
  }
  aDivs[0].onmouseout = function(){
      
      startMove(this, "opacity", 30, function(){
          startMove(this, "height", 100, function(){
              startMove(this, "width", 100);
          })
      });
  }
}
  • 回调函数
    我们把函数当做参数传入,并且在合适调用的方式,叫做回调函数。在别的编程语言(C语言、C++)叫做函数指针。
function startMove(node, attr, iTarget, complete){//complete = show;
   clearInterval(node.timer);
   node.timer = setInterval(function(){
       //计算速度
       var iCur = null;
       if(attr == "opacity"){
           iCur = parseInt(parseFloat(getStyle(node, "opacity")) * 100);
       }else{
           iCur = parseInt(getStyle(node, attr))
       }
       
       var speed = (iTarget - iCur) / 8;
       speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);

       if(iCur == iTarget){
           clearInterval(node.timer);
           if(complete){
               complete.call(node);
           }
           // alert("运动结束了");
           /* 
               当运动结束以后,应该做什么的代码在这里不能写死。
               【注】封装函数,形参,根据函数不确定的值决定的。
               可以,将一段代码编写的权利交给别人。声明一个形参,这个形参是用来接收,从外面封装好的一个函数的。
           */
       }else{
           if(attr == "opacity"){
               iCur += speed;
               node.style.opacity = iCur / 100;
               node.style.filter = "alpha(opacity=" + iCur +  ")";
           }else{
               node.style[attr] = iCur + speed + 'px';
           }
       }
   }, 30);
}

多出来的一个参数,只有传进去的时候才调用
鼠标移入变宽,结束之后弹出abc
先横向展开.再以向展开
鼠标移出,先变回不透明,变矮,变窄

五、封装运动框架

  1. 认识运动(运动框架)
    <1>每次启动定时器,将上一次定时器关闭
    <2>运动和停止 if…else
  2. 分享到菜单和淡入淡出
    startMove(iTarget);
  3. 缓冲运动
    var speed = (iTarget - iCur) / 8;
    speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
  4. 多物体运动
    node.timer;
    多物体淡入淡出:任何一个变量都不能公用
    startMove(node, iTarget);
  5. 多物体多样式运动
    offset系列 透明度
    startMove(node, attr, iTarget);
  6. 链式运动
    startMove(node, attr, iTarget, complete)
  7. 完美运动
    startMove(node, cssObject, complete);

六、运动框架的应用

1. banner图

  • 编写图片div
<body>
        <div id = 'div1'>
            <ul id = 'ul1'>
                <li>
                    <img src="img/1.jpg" alt=""/>
                </li>
                <li>
                    <img src="img/2.jpg" alt=""/>
                </li>
                <li>
                    <img src="img/3.jpg" alt=""/>
                </li>
                <li>
                    <img src="img/4.jpg" alt=""/>
                </li>
            </ul>
        </div>
    </body>
  • 设计div样式
<style>
            *{margin: 0px; padding: 0px}
            #ul1 li{list-style: none; width: 200px; height: 200px; margin: 10px; float: left;}
            #ul1 li img{width: 100%; height: 100%}
            #ul1 {position: absolute; left: 0px}
            #div1{width: 880px; height: 220px; border: 1px solid black; margin: 150px auto; position: relative; overflow: hidden;}
        </style>
  • js代码:
  • 调用startMove()函数
  • 【tips】将四张图片添加到末尾;若滚动四张结束,则设置left = 0px ; 回到第一张。
<script src = "../startMove.js"></script>
        <script>
            window.onload = function(){
                var oUl1 = document.getElementById("ul1");
                var oDiv1 = document.getElementById("div1");

                /* 
                    直接把这四张图片再添加到末尾
                */
                oUl1.innerHTML += oUl1.innerHTML;
                //重新设置一下ul的宽
                oUl1.style.width = 220 * 8 + 'px';

                setInterval(function(){
                    //让ul向左运动一个图片的宽
                    startMove(oUl1, {left: oUl1.offsetLeft - 220}, function(){
                        if(oUl1.offsetLeft <= -oUl1.offsetWidth / 2){
                            oUl1.style.left = "0px";
                        }
                    })
                }, 2000);
            }
        </script>

2. 打砖块

  • 页面中 球、砖块、滑块
<body>
    <div id = 'div1'>
        <div id = 'ball'></div>
        <div id = 'bat'></div>
        <div id = 'brick'>
            <!-- <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div> -->
        </div>
    </div>
</body>
  • 样式
 <style>
     #div1{width: 600px; height: 600px; border: 1px solid black; position: relative; margin: 100px auto}
     #ball{width: 20px; height: 20px; background-color: red; border-radius: 50%; position: absolute; bottom: 30px; left: 290px}
     #bat{width: 100px; height: 30px; background-color: blue; position: absolute; bottom: 0px; left: 250px}
     #brick div{width: 98px; height: 18px; border: 1px solid black; float: left;}
 </style>
        <script>
            window.onload = function(){
                var oDiv = document.getElementById("div1");
                var oBall = document.getElementById("ball");
                var oBat = document.getElementById("bat");
                var oBrick = document.getElementById("brick");
                var aBricks = oBrick.getElementsByTagName("div");

                dragX(oBat);
                createBrick(60);

                //让小球可以水平方向运动,随机一个水平方向的速度
                var speedX = parseInt(Math.random() * 4) + 3;
                //随机一个垂直方向的速度
                var speedY = -(parseInt(Math.random() * 3) + 5);
                

                setInterval(function(){
                    oBall.style.left = oBall.offsetLeft + speedX + 'px';
                    oBall.style.top = oBall.offsetTop + speedY + 'px';
                    if(oBall.offsetLeft >= 580 || oBall.offsetLeft <= 0){
                        speedX *= -1;
                    }

                    if(oBall.offsetTop <= 0){
                        speedY *= -1;
                    }
                    if(oBall.offsetTop >= 580){
                        alert("GAME OVER");
                        window.location.reload();
                    }

                    /* 
                        进行碰撞检测
                    */
                   //1、小球和拍子的碰撞检测
                   if(konck(oBall, oBat)){
                       speedY *= -1;
                   }
                   //2、小球和砖块发生碰撞
                   for(var i = 0; i < aBricks.length; i++){
                       if(konck(aBricks[i], oBall)){
                           speedY *= -1;
                           //砖块要被删除
                           oBrick.removeChild(aBricks[i]);
                           break;
                       }
                   }

                }, 30);
            }

  • 有限制的拖拽
            function dragX(node){
                node.onmousedown = function(ev){
                    var e = ev || window.event;
                    var offsetX = e.clientX - node.offsetLeft;
                    document.onmousemove = function(ev){
                        var e = ev || window.event;
                        var l = e.clientX - offsetX;
                        //限制出界
                        if(l <= 0){
                            l = 0;
                        }
                        if(l >= 500){
                            l = 500;
                        }
                        node.style.left = l + 'px';
                    }
                }
                document.onmouseup = function(){
                    document.onmousemove = null;
                }
            }

  • 文档流的转换:相对定位 转 绝对定位
  • aBricks[i].style.position = ‘absolute’;
            //创建砖块  n的意思是创建n个砖块
            /* 
               文档流的转换:
               相对定位  转   绝对定位
            */
            function createBrick(n){
                var oBrick = document.getElementById("brick");
                for(var i = 0; i < n; i++){
                    var node = document.createElement("div");
                    node.style.backgroundColor = randomColor();
                    oBrick.appendChild(node);
                }
                //文档流转换
                var aBricks = oBrick.getElementsByTagName("div");
                for(var i = 0; i < aBricks.length; i++){
                    aBricks[i].style.left = aBricks[i].offsetLeft + 'px';
                    aBricks[i].style.top = aBricks[i].offsetTop + 'px'; 
                }
                for(var i = 0; i < aBricks.length; i++){
                    aBricks[i].style.position = 'absolute';
                }
            }
  • 砖块随机颜色
            function randomColor(){
                var str = "rgba(" + parseInt(Math.random() * 256) + "," + parseInt(Math.random() * 256) + "," + parseInt(Math.random() * 256) + ",1)";
                return str;
            }
  • 判断是否碰撞
            /* 
                思路:找到如何是绝对碰不上的。
            */
            function  konck(node1, node2){
                var l1 = node1.offsetLeft;
                var r1 = node1.offsetLeft + node1.offsetWidth;
                var t1 = node1.offsetTop;
                var b1 = node1.offsetTop + node1.offsetHeight;

                var l2 = node2.offsetLeft;
                var r2 = node2.offsetLeft + node2.offsetWidth;
                var t2 = node2.offsetTop;
                var b2 = node2.offsetTop + node2.offsetHeight;

                if(l2 > r1 || r2 < l1 || t2 > b1 || b2 < t1){
                    return false;
                }else{
                    return true;
                }
            }

3. 多图片缩放(九宫格)

  • 九宫格布局
    • 布局的时候:相对定位
    • 实际放大的时候:必须绝对定位
    • 文档流的转换:相对定位 => 绝对定位
window.onload = function(){
   var oUl1 = document.getElementById("ul1");
   var aLis = oUl1.getElementsByTagName('li');

   var currentIndex = 2;

//设置绝对定位  否则格子会重叠在一起
   for(var i = 0; i < aLis.length; i++){
       aLis[i].style.left = aLis[i].offsetLeft + 'px';
       aLis[i].style.top = aLis[i].offsetTop + 'px';
       var oImg = document.createElement("img");
       oImg.src = "img/" + (i + 1) + ".jpg";
       aLis[i].appendChild(oImg);
   }
   for(var i = 0; i < aLis.length; i++){
       aLis[i].style.position = 'absolute';
       aLis[i].style.margin = '0px';

//给每一个li标签添加移入移出
       aLis[i].onmouseover = function(){
   //zIndex 后面的格子优先级更高,样式不被前面的影响
           this.style.zIndex = currentIndex++; 
           startMove(this, {
               width: 200,
               height: 200,
               marginLeft: -50,
               marginTop: -50
           })
       }
       aLis[i].onmouseout = function(){
           startMove(this, {
               width: 100,
               height: 100,
               marginLeft: 0,
               marginTop: 0
           })
       }
   }
}
  • 从中间放大的方法
<script src = '../startMove.js'></script>
<script>
    window.onload = function(){
        var oDiv1 = document.getElementById("div1");
        oDiv1.onmouseover = function(){
            startMove(this, {width: 200, height: 200, marginLeft: -50, marginTop: -50});
        }
        oDiv1.onmouseout = function(){
            startMove(this, {width: 100, height: 100, marginLeft: 0, marginTop: 0});
        }
    }
</script>

4. 抛物线运动

  • 引入parabola.js 、jquery.js
var i = 0;
window.onload = function(){
	var bool = new Parabola({
	    el: "#boll",  		   //选择我们哪个物体需要进行抛物线运动
	    offset: [500, 100],    //初始位置和最终,到达的偏移的坐标
	    curvature: 0.001,      //抛物线弯曲的曲率,越接近于0,就越平缓 
	    duration: 1000,        //整个动画所用的时间
	    callback:function(){
	    					   //这个函数是在整个动画结束的时候调用
	        alert("完成后回调")
	    },
	    stepCallback:function(x,y){
	    			           //这是在运动过程中不断去调用的函数
	        console.log(x,y);
	        $("<div>").appendTo("body").css({
	            "position": "absolute",
	            "top": this.elOriginalTop + y,
	            "left":this.elOriginalLeft + x,
	            "background-color":"#CDCDCD",
	            "width":"5px",
	            "height":"5px",
	            "border-radius": "5px"
	        });
	    }
	});


	$("#reset").click(function (event) {
	    event.preventDefault();
	    bool.reset()  //将位置重置
	});
	$("#run").click(function (event) {
	    event.preventDefault();
	    bool.start(); //动画开始
	});
	$("#stop").click(function (event) {
	    event.preventDefault();
	    bool.stop();  //动画停止
	});
	$("#setOptions").click(function (event) {
	    event.preventDefault();
	    bool.setOptions({
	        targetEl: $("#target"), //必须元素节点 设置,小球运动到该元素节点的位置
	        curvature: 0.005,
	        duration: 1000
	    });
	});
}

5. 评分特效

  • 圆周运动
    1. 确定圆心
    2. 定半径
    3. 旋转(顺时针)
    4. 1弧度 = Math.PI / 180;
window.onload = function(){
    var oDiv = document.getElementById("div1");

    var X = 500;
    var Y = 400;

    var r = 100;
    var i = 0; //代表转过的弧度
    setInterval(function(){
        i++;
        var radian = i * Math.PI / 180;
        var a = Math.sin(radian) * r;
        var b = Math.cos(radian) * r;

        oDiv.style.left = X + a + 'px';
        oDiv.style.top = Y - b + 'px';

        
        //显示当前圆周运动的轨迹
        var node = document.createElement("div");
        node.style.width = "5px";
        node.style.height = "5px";
        node.style.backgroundColor = 'black';
        node.style.position = 'absolute';
        node.style.left = oDiv.offsetLeft + 'px';
        node.style.top = oDiv.offsetTop + 'px';
        document.body.appendChild(node);

    }, 30);
}
</script>
  • 完美运动
    • 宽高透明度同时发生变化
window.onload = function(){
    var oDiv1 = document.getElementById("div1");
    /* 
        宽高透明度同时发生变化
     */
    oDiv1.onmouseover = function(){
        startMove(this, {
            width: 300,
            height: 102,
            opacity: 30
        }, function(){
            alert("动画结束了");
        });
        
    }

    oDiv1.onmouseout = function(){
        startMove(this, {
            width: 100,
            height: 100,
            opacity: 100
        });
    }
}
  • 回调函数:我们把函数当做参数传入,并且在合适调用的方式,叫做回调函数。在别的编程语言(C语言、C++)叫做函数指针。
    问题:其中有一个动画到达目的值,就把定时器关闭掉了。
    解决:当所有的动画到达目的值,才能关闭定时器
function startMove(node, cssObj, complete){//complete = show;
    clearInterval(node.timer);
    node.timer = setInterval(function(){
        var isEnd = true; //假设所有的动画都到达目的值。
        for(var attr in cssObj){
            var iTarget = cssObj[attr];
            //计算速度
            var iCur = null;
            if(attr == "opacity"){
                iCur = parseInt(parseFloat(getStyle(node, "opacity")) * 100);
            }else{
                iCur = parseInt(getStyle(node, attr))
            }
            
            var speed = (iTarget - iCur) / 8;
            speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);

            
            if(attr == "opacity"){
                iCur += speed;
                node.style.opacity = iCur / 100;
                node.style.filter = "alpha(opacity=" + iCur +  ")";
            }else{
                node.style[attr] = iCur + speed + 'px';
            }  

            if(iCur != iTarget){
                isEnd = false;
            }
        }

        if(isEnd){
            clearInterval(node.timer);
            if(complete){
                complete.call(node);
            }
        }
    }, 30);
}
  • 获取当前有效样式浏览器兼容的写法
function getStyle(node, cssStr){
    return node.currentStyle ? node.currentStyle[cssStr] : getComputedStyle(node)[cssStr];
}
  • 设置样式 node.style[attr] = value;
            window.onload = function(){
                var oDiv1 = document.getElementById("div1");
                oDiv1.onclick = function(){
                    setStyle(this, "width", "300px");
                    setStyle(this, "height", "300px");
                    setStyle(this, "backgroundColor", 'blue');
                }
            }

            //设置css样式  必须去使用这个方法进行修改
            function setStyle(node, attr, value){
                node.style[attr] = value;
            }
  • 需要传入多个样式,变成一个对象传入就OK
<script>
   window.onload = function(){
       var oDiv1 = document.getElementById("div1");
       oDiv1.onclick = function(){
           setStyle(this, {
               width: "300px",
               height: "300px",
               backgroundColor: 'blue'
           })
       }
   }
   //设置css样式  必须去使用这个方法进行修改
   function setStyle(node, cssObj){
       for(var attr in cssObj){
           //node.style["width"] = "100px";
           node.style[attr] = cssObj[attr];
       }
   }
</script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值