• [js高手之路]打造通用的匀速运动框架


    本文,是接着上文[js高手之路]匀速运动与实例实战(侧边栏,淡入淡出)继续的,在这篇文章的最后,我们做了2个小实例:侧边栏与改变透明度的淡入淡出效果,本文我们把上文的animate函数,继续改造,让他变得更加的通用和强大:

    1,支持多个物体的运动

    2,同时运动

    3,顺序运动

    这三种运动方式也是jquery中animate函数支持的

    一、animate函数中怎么区分变化不同的样式?

    上文中,侧边栏效果 用的animate函数 改变的是left值

     1 function animate(obj, target, speed) {
     2     clearInterval(timer);
     3     timer = setInterval(function () {
     4         if (obj.offsetLeft == target) {
     5             clearInterval(timer);
     6         } else {
     7             obj.style.left = obj.offsetLeft + speed + 'px';
     8         }
     9     }, 30);
    10 }

    淡入淡出效果 用的animate函数 改变的是透明度

     1             function animate(obj, target, speed) {
     2                 clearInterval(timer);
     3                 var cur = 0;
     4                 timer = setInterval(function () {
     5                     cur = css( obj, 'opacity') * 100;
     6                     if( cur == target ){
     7                        clearInterval( timer );
     8                     }else {
     9                         cur += speed;
    10                         obj.style.opacity = cur / 100;
    11                         obj.style.filter = "alpha(opacity:" + cur + ")";
    12                     }
    13                 }, 30);
    14             }

    而我们封装的函数,要变成通用的,首先面临的问题就是 这个函数要同时支持left值和透明度的变化,更通用的做法应该是要支持所有的样式变化,比如轮播功能,他有左右滑动,也有上下滑动。

    我们可以在获取样式和改变样式的时候,做一下判断就可以了,判断分2类就能达到目的,因为其他样式( margin, left, top, right, font-size等等 )都是px,而透明度没有px单位

     1 function animate(obj, attr, target, speed) {
     2     clearInterval(timer);
     3     var cur = 0;
     4     timer = setInterval(function () {
     5         if (attr == 'opacity') {
     6             cur = css(obj, 'opacity') * 100;
     7         } else {
     8             cur = parseInt(css(obj, attr));
     9         }
    10 
    11         if (cur == target) {
    12             clearInterval(timer);
    13         } else {
    14             if (attr == 'opacity') {
    15                 obj.style.opacity = ( cur + speed ) / 100;
    16                 obj.style.filter = "alpha(opacity:" + (cur + speed) + ")";
    17             } else {
    18                 obj.style[attr] = cur + speed + "px";
    19             }
    20         }
    21     }, 30);
    22 }

    合并之后的animate相比之前多了一个参数attr, 这个参数就是变化的样式,obj: 变化的对象, target: 样式需要变化到的目标值.  speed: 样式每次变化的大小

    如:

    oImg.onmouseover = function () {
      animate(this, 'opacity', 100, 10);
    }
    oImg是获取到的图片对象. 这里各参数意思如下:
    this:当前图片对象
    opacity: 变化的样式是透明度
    100: 鼠标移到图片上时,透明度变成100
    10: 透明度每次在原来的基础上加10
     1 <!doctype html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>合并的运动 - by ghostwu</title>
     6     <style>
     7         img {
     8             border: none;
     9             opacity: 0.3;
    10             filter: alpha(opacity:30);
    11             position: absolute;
    12             left: 200px;
    13         }
    14 
    15         #box {
    16              150px;
    17             height: 300px;
    18             background: red;
    19             position: absolute;
    20             left: -150px;
    21             top: 50px;
    22         }
    23 
    24         #box div {
    25              28px;
    26             height: 100px;
    27             position: absolute;
    28             right: -28px;
    29             top: 100px;
    30             background: green;
    31         }
    32     </style>
    33     <script>
    34         window.onload = function () {
    35             var oImg = document.getElementById("img"),
    36                 oBox = document.getElementById("box"),
    37                 timer = null;
    38 
    39             oImg.onmouseover = function () {
    40                 animate(this, 'opacity', 100, 10);
    41             }
    42             oImg.onmouseout = function () {
    43                 animate(this, 'opacity', 30, -10);
    44             }
    45 
    46             oBox.onmouseover = function () {
    47                 animate(this, 'left', 0, 10);
    48             }
    49 
    50             oBox.onmouseout = function () {
    51                 animate(this, 'left', -150, -10);
    52             }
    53 
    54             function animate(obj, attr, target, speed) {
    55                 clearInterval(timer);
    56                 var cur = 0;
    57                 timer = setInterval(function () {
    58                     if (attr == 'opacity') {
    59                         cur = css(obj, 'opacity') * 100;
    60                     } else {
    61                         cur = parseInt(css(obj, attr));
    62                     }
    63 
    64                     if (cur == target) {
    65                         clearInterval(timer);
    66                     } else {
    67                         if (attr == 'opacity') {
    68                             obj.style.opacity = ( cur + speed ) / 100;
    69                             obj.style.filter = "alpha(opacity:" + (cur + speed) + ")";
    70                         } else {
    71                             obj.style[attr] = cur + speed + "px";
    72                         }
    73                     }
    74                 }, 30);
    75             }
    76 
    77             function css(obj, attr) {
    78                 if (obj.currentStyle) {
    79                     return obj.currentStyle[attr];
    80                 } else {
    81                     return getComputedStyle(obj, false)[attr];
    82                 }
    83             }
    84         }
    85     </script>
    86 </head>
    87 <body>
    88 <div id="box">
    89     <div>分享到</div>
    90 </div>
    91 <img src="./img/h4.jpg" alt="" id="img"/>
    92 </body>
    93 </html>
    View Code

    上述就是完整的代码实例,请自行展开,点击run code预览效果 


     
    当你分别测试这两个功能的时候:
    移动到图片上然后移出来
    移动到分享到,然后移出来
    这样是没有问题的
     
    如果你这样测试:
    移动到 分享到,然后迅速又移动到图片上, 这个时候你会发现 分享到 停下来了,这就不符合逻辑了! 按道理来说,鼠标移动到图片上,相当于触发了 “分享到” 的mouseout( 鼠标移出事件 ),那么  "分享到" 这个时候要隐藏,并不是停止。 为什么会这样呢?因为这两个运动共享了一个定时器,当鼠标移动到图片上,开启定时器的时候,把“分享到”的定时器给停了。那么再做多物体运动的时候,我们就要把定时器拆分,每个对象都要有一个定时器,怎么做呢? 非常简单,不要定义一个简单的timer变量,我们只要把timer加在obj对象上,那么每个对象都有一个timer属性,就达到定时器的分离效果了
    修改之后的完整代码如下,请自行展开:
     1 <!doctype html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>Document</title>
     6     <style>
     7         img {
     8             border: none;
     9             opacity: 0.3;
    10             filter: alpha(opacity:30);
    11             position: absolute;
    12             left: 200px;
    13         }
    14 
    15         #box {
    16              150px;
    17             height: 300px;
    18             background: red;
    19             position: absolute;
    20             left: -150px;
    21             top: 50px;
    22         }
    23 
    24         #box div {
    25              28px;
    26             height: 100px;
    27             position: absolute;
    28             right: -28px;
    29             top: 100px;
    30             background: green;
    31         }
    32     </style>
    33     <script>
    34         window.onload = function () {
    35             var oImg = document.getElementById("img"),
    36                 oBox = document.getElementById("box");
    37 
    38             oImg.onmouseover = function () {
    39                 animate(this, 'opacity', 100, 10);
    40             }
    41             oImg.onmouseout = function () {
    42                 animate(this, 'opacity', 30, -10);
    43             }
    44 
    45             oBox.onmouseover = function () {
    46                 animate(this, 'left', 0, 10);
    47             }
    48 
    49             oBox.onmouseout = function () {
    50                 animate(this, 'left', -150, -10);
    51             }
    52 
    53             function animate(obj, attr, target, speed) {
    54                 clearInterval(obj.timer);
    55                 var cur = 0;
    56                 obj.timer = setInterval(function () {
    57                     if (attr == 'opacity') {
    58                         cur = css(obj, 'opacity') * 100;
    59                     } else {
    60                         cur = parseInt(css(obj, attr));
    61                     }
    62 
    63                     if (cur == target) {
    64                         clearInterval(obj.timer);
    65                     } else {
    66                         if (attr == 'opacity') {
    67                             obj.style.opacity = ( cur + speed ) / 100;
    68                             obj.style.filter = "alpha(opacity:" + (cur + speed) + ")";
    69                         } else {
    70                             obj.style[attr] = cur + speed + "px";
    71                         }
    72                     }
    73                 }, 30);
    74             }
    75 
    76             function css(obj, attr) {
    77                 if (obj.currentStyle) {
    78                     return obj.currentStyle[attr];
    79                 } else {
    80                     return getComputedStyle(obj, false)[attr];
    81                 }
    82             }
    83         }
    84     </script>
    85 </head>
    86 <body>
    87 <div id="box">
    88     <div>分享到</div>
    89 </div>
    90 <img src="./img/h4.jpg" alt="" id="img"/>
    91 </body>
    92 </html>
    View Code

    至此,我们就完成了多物体运动与不同样式的修改

    二、让animate函数支持多个样式同时改变

    比如:

    oBox.onmouseover = function(){
      animate( this, { "width" : 500, "height" : 400 }, 10 );
    }

    oBox是一个div元素,animate各参数的意思:

    this: 当前div元素

    {width : 500, "height" : 400 } : 把宽度变成500, 高度变成400,这两个样式要在同一时间完成,

    10: 样式每次在原来的基础上变化10(如width初始值200--> 210, 220, 230.....)

    完整的同时运动变化 代码:

     1 <!doctype html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>Document</title>
     6     <style>
     7     div {
     8          200px;
     9         height: 200px;
    10         background: red;
    11     }
    12     </style>
    13     <script>
    14         window.onload = function () {
    15             var oBox = document.getElementById("box");
    16             oBox.onmouseover = function(){
    17 //                animate( this, { "width" : 500, "height" : 500 }, 10 );
    18                 animate( this, { "width" : 500, "height" : 400 }, 10 );
    19             }
    20 
    21             function animate(obj, attr, speed) {
    22                 clearInterval(obj.timer);
    23                 var cur = 0;
    24                 obj.timer = setInterval(function () {
    25                     for ( var key in attr ) {
    26                         if (key == 'opacity') {
    27                             cur = css(obj, 'opacity') * 100;
    28                         } else {
    29                             cur = parseInt(css(obj, key));
    30                         }
    31                         var target = attr[key];
    32                         if (cur == target) {
    33                             clearInterval(obj.timer);
    34                         } else {
    35                             if (key == 'opacity') {
    36                                 obj.style.opacity = ( cur + speed ) / 100;
    37                                 obj.style.filter = "alpha(opacity:" + (cur + speed) + ")";
    38                             } else {
    39                                 obj.style[key] = cur + speed + "px";
    40                             }
    41                         }
    42                     }
    43                 }, 30);
    44             }
    45 
    46             function css(obj, attr) {
    47                 if (obj.currentStyle) {
    48                     return obj.currentStyle[attr];
    49                 } else {
    50                     return getComputedStyle(obj, false)[attr];
    51                 }
    52             }
    53         }
    54     </script>
    55 </head>
    56 <body>
    57     <div id="box"></div>
    58 </body>
    59 </html>
    View Code

    请自行展开这段代码,这段代码能够同时运动,但是有一个问题:

    div的初始宽度与高度( width : 200, height : 200)

    变化步长一样( 10 )

    变化时间一样( 每30毫秒变化一次 )

    目标( 500, height : 400 )

    你能想到什么问题吗?( 两个人在同一起跑线上,速度一样, 时间一样,但是要同时到达不同的目标,一个500, 一个400 )

    答案是很明显的,肯定是目标近的( height : 400 )那个先到达,然后把对象上的定时器关了,另一个目标更远的( 500 )肯定到达不了

    你可以在这句代码下面,输出当前的值和目标值:

    var target = attr[key];
    console.log( key, cur, target );

    输出来的结果是:

     从上图可以看出,height已经达到了400px,但是width停在了410px,为什么不是400px ? 因为width = 400的时候, 就是( cur == 500 ) 相当于( 400 == 500 ) 不成立,所以执行了else语句,width = cur + 10 = 400 + 10 = 410,然后height到达400px停止了定时器,所以width停在了410px.

    那么我们怎么解决这个问题呢?

    其实也好办,就是height = 400的时候 不要把定时器关了,应该等width = 500的时候再关闭定时器,不就在同一时间,完成了同时到达目标的效果吗?

    修改后的代码如下:

     1 <!doctype html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>Document</title>
     6     <style>
     7     div {
     8          200px;
     9         height: 200px;
    10         background: red;
    11     }
    12     </style>
    13     <script>
    14         window.onload = function () {
    15             var oBox = document.getElementById("box");
    16             oBox.onmouseover = function(){
    17                 animate( this, { "width" : 500, "height" : 400 }, 10 );
    18             }
    19 
    20             function animate(obj, attr, speed) {
    21                 clearInterval(obj.timer);
    22                 var cur = 0;
    23                 obj.timer = setInterval(function () {
    24                     var bFlag = true;
    25                     for ( var key in attr ) {
    26                         if (key == 'opacity') {
    27                             cur = css(obj, 'opacity') * 100;
    28                         } else {
    29                             cur = parseInt(css(obj, key));
    30                         }
    31                         var target = attr[key];
    32                         if (cur != target) {
    33                             bFlag = false;
    34                             if (key == 'opacity') {
    35                                 obj.style.opacity = ( cur + speed ) / 100;
    36                                 obj.style.filter = "alpha(opacity:" + (cur + speed) + ")";
    37                             } else {
    38                                 obj.style[key] = cur + speed + "px";
    39                             }
    40                         }
    41                     }
    42                     if ( bFlag ) {
    43                         clearInterval( obj.timer );
    44                     }
    45                 }, 30);
    46             }
    47 
    48             function css(obj, attr) {
    49                 if (obj.currentStyle) {
    50                     return obj.currentStyle[attr];
    51                 } else {
    52                     return getComputedStyle(obj, false)[attr];
    53                 }
    54             }
    55         }
    56     </script>
    57 </head>
    58 <body>
    59     <div id="box"></div>
    60 </body>
    61 </html>
    View Code

    声明一个变量,每次变化完一次( width, height )样式 把bFlag = true, 只要在for循环中有一个没有到达目标,bFlag的值都是false,这样就不会关闭定时器。当两个都到达目标,才关闭定时器.

    三、顺序运动

     如样式变化,按顺序来,不是同时变化, 如:

    oBox.onmouseover = function(){
    //回调函数: 把函数当做参数传递给另一个函数
      animate( this, { 'width' : 500 }, 10, function(){
        animate( this, { 'height' : 500 }, 10 );
      } );
    }

    当把width变成500px的时候,如果传递了回调函数, 再接着执行回调函数里面的运动

    修改后的完整代码:

     1 <!DOCTYPE html>
     2 <html>
     3 <head lang="en">
     4     <meta charset="UTF-8">
     5     <title>通用的匀速运动框架 - by ghostwu</title>
     6     <style>
     7         div {
     8              200px;
     9             height: 200px;
    10             background: red;
    11         }
    12     </style>
    13     <script>
    14         window.onload = function () {
    15             var oBox = document.getElementById("box");
    16             oBox.onmouseover = function(){
    17                 //回调函数: 把函数当做参数传递给另一个函数
    18                 animate( this, { 'width' : 500 }, 10, function(){
    19                     animate( this, { 'height' : 500 }, 10 );
    20                 } );
    21             }
    22 
    23             function animate(obj, attr, speed, fn ) {
    24 
    25                 clearInterval(obj.timer);
    26                 var cur = 0;
    27                 obj.timer = setInterval(function () {
    28                     var bFlag = true;
    29                     for (var key in attr) {
    30                         if (key == 'opacity') {
    31                             cur = css(obj, 'opacity') * 100;
    32                         } else {
    33                             cur = parseInt(css(obj, key));
    34                         }
    35                         var target = attr[key];
    36                         if (cur != target) {
    37                             bFlag = false;
    38                             if (key == 'opacity') {
    39                                 obj.style.opacity = ( cur + speed ) / 100;
    40                                 obj.style.filter = "alpha(opacity:" + (cur + speed) + ")";
    41                             } else {
    42                                 obj.style[key] = cur + speed + "px";
    43                             }
    44                         }
    45                     }
    46 
    47                     if (bFlag) {
    48                         clearInterval(obj.timer);
    49                         fn && fn.call( obj );
    50                     }
    51                 }, 30);
    52             }
    53 
    54             function css(obj, attr) {
    55                 if (obj.currentStyle) {
    56                     return obj.currentStyle[attr];
    57                 } else {
    58                     return getComputedStyle(obj, false)[attr];
    59                 }
    60             }
    61         }
    62     </script>
    63 </head>
    64 <body>
    65 <div id="box"></div>
    66 </body>
    67 </html>
    View Code

      

  • 相关阅读:
    pku3486Computers 动态规划
    pku2229sumsets(zjgsu,分花)
    pku2663Tri Tiling递推题
    pku1015Jury Compromise 动态规划
    pku3508Hide That Number一道加密算法题
    pku动态规划题目列表
    浅谈XXE攻击
    PHP核心配置详解
    SSRF漏洞用到的其他协议(dict协议,file协议)
    php中使用CURL之php curl详解
  • 原文地址:https://www.cnblogs.com/ghostwu/p/7670033.html
Copyright © 2020-2023  润新知