打造通用的匀速运动框架(实例讲解)


Posted in Javascript onOctober 17, 2017

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

1,支持多个物体的运动

2,同时运动

3,顺序运动

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

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

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

function animate(obj, target, speed) {
 clearInterval(timer);
 timer = setInterval(function () {
 if (obj.offsetLeft == target) {
  clearInterval(timer);
 } else {
  obj.style.left = obj.offsetLeft + speed + 'px';
 }
 }, 30);
}

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

function animate(obj, target, speed) {
  clearInterval(timer);
  var cur = 0;
  timer = setInterval(function () {
   cur = css( obj, 'opacity') * 100;
   if( cur == target ){
   clearInterval( timer );
   }else {
   cur += speed;
   obj.style.opacity = cur / 100;
   obj.style.filter = "alpha(opacity:" + cur + ")";
   }
  }, 30);
  }

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

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

function animate(obj, attr, target, speed) {
 clearInterval(timer);
 var cur = 0;
 timer = setInterval(function () {
 if (attr == 'opacity') {
  cur = css(obj, 'opacity') * 100;
 } else {
  cur = parseInt(css(obj, attr));
 }

 if (cur == target) {
  clearInterval(timer);
 } else {
  if (attr == 'opacity') {
  obj.style.opacity = ( cur + speed ) / 100;
  obj.style.filter = "alpha(opacity:" + (cur + speed) + ")";
  } else {
  obj.style[attr] = cur + speed + "px";
  }
 }
 }, 30);
}

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

如:

oImg.onmouseover = function () {
animate(this, 'opacity', 100, 10);
}

oImg是获取到的图片对象. 这里各参数意思如下:

this:当前图片对象

opacity: 变化的样式是透明度

100: 鼠标移到图片上时,透明度变成100

10: 透明度每次在原来的基础上加10

<!doctype html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>合并的运动 - by ghostwu</title>
 <style>
 img {
  border: none;
  opacity: 0.3;
  filter: alpha(opacity:30);
  position: absolute;
  left: 200px;
 }

 #box {
  width: 150px;
  height: 300px;
  background: red;
  position: absolute;
  left: -150px;
  top: 50px;
 }

 #box div {
  width: 28px;
  height: 100px;
  position: absolute;
  right: -28px;
  top: 100px;
  background: green;
 }
 </style>
 <script>
 window.onload = function () {
  var oImg = document.getElementById("img"),
  oBox = document.getElementById("box"),
  timer = null;

  oImg.onmouseover = function () {
  animate(this, 'opacity', 100, 10);
  }
  oImg.onmouseout = function () {
  animate(this, 'opacity', 30, -10);
  }

  oBox.onmouseover = function () {
  animate(this, 'left', 0, 10);
  }

  oBox.onmouseout = function () {
  animate(this, 'left', -150, -10);
  }

  function animate(obj, attr, target, speed) {
  clearInterval(timer);
  var cur = 0;
  timer = setInterval(function () {
   if (attr == 'opacity') {
   cur = css(obj, 'opacity') * 100;
   } else {
   cur = parseInt(css(obj, attr));
   }

   if (cur == target) {
   clearInterval(timer);
   } else {
   if (attr == 'opacity') {
    obj.style.opacity = ( cur + speed ) / 100;
    obj.style.filter = "alpha(opacity:" + (cur + speed) + ")";
   } else {
    obj.style[attr] = cur + speed + "px";
   }
   }
  }, 30);
  }

  function css(obj, attr) {
  if (obj.currentStyle) {
   return obj.currentStyle[attr];
  } else {
   return getComputedStyle(obj, false)[attr];
  }
  }
 }
 </script>
</head>
<body>
<div id="box">
 <div>分享到</div>
</div>
<img src="./img/h4.jpg" alt="" id="img"/>
</body>
</html>

上述就是完整的代码实例。

当你分别测试这两个功能的时候:

移动到图片上然后移出来

移动到分享到,然后移出来

这样是没有问题的

如果你这样测试:

移动到 分享到,然后迅速又移动到图片上, 这个时候你会发现 分享到 停下来了,这就不符合逻辑了! 按道理来说,鼠标移动到图片上,相当于触发了 “分享到” 的mouseout( 鼠标移出事件 ),那么 "分享到" 这个时候要隐藏,并不是停止。 为什么会这样呢?因为这两个运动共享了一个定时器,当鼠标移动到图片上,开启定时器的时候,把“分享到”的定时器给停了。那么再做多物体运动的时候,我们就要把定时器拆分,每个对象都要有一个定时器,怎么做呢? 非常简单,不要定义一个简单的timer变量,我们只要把timer加在obj对象上,那么每个对象都有一个timer属性,就达到定时器的分离效果了

修改之后的完整代码如下,请自行展开:

<!doctype html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Document</title>
 <style>
 img {
  border: none;
  opacity: 0.3;
  filter: alpha(opacity:30);
  position: absolute;
  left: 200px;
 }

 #box {
  width: 150px;
  height: 300px;
  background: red;
  position: absolute;
  left: -150px;
  top: 50px;
 }

 #box div {
  width: 28px;
  height: 100px;
  position: absolute;
  right: -28px;
  top: 100px;
  background: green;
 }
 </style>
 <script>
 window.onload = function () {
  var oImg = document.getElementById("img"),
  oBox = document.getElementById("box");

  oImg.onmouseover = function () {
  animate(this, 'opacity', 100, 10);
  }
  oImg.onmouseout = function () {
  animate(this, 'opacity', 30, -10);
  }

  oBox.onmouseover = function () {
  animate(this, 'left', 0, 10);
  }

  oBox.onmouseout = function () {
  animate(this, 'left', -150, -10);
  }

  function animate(obj, attr, target, speed) {
  clearInterval(obj.timer);
  var cur = 0;
  obj.timer = setInterval(function () {
   if (attr == 'opacity') {
   cur = css(obj, 'opacity') * 100;
   } else {
   cur = parseInt(css(obj, attr));
   }

   if (cur == target) {
   clearInterval(obj.timer);
   } else {
   if (attr == 'opacity') {
    obj.style.opacity = ( cur + speed ) / 100;
    obj.style.filter = "alpha(opacity:" + (cur + speed) + ")";
   } else {
    obj.style[attr] = cur + speed + "px";
   }
   }
  }, 30);
  }

  function css(obj, attr) {
  if (obj.currentStyle) {
   return obj.currentStyle[attr];
  } else {
   return getComputedStyle(obj, false)[attr];
  }
  }
 }
 </script>
</head>
<body>
<div id="box">
 <div>分享到</div>
</div>
<img src="./img/h4.jpg" alt="" id="img"/>
</body>
</html>

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

二、让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.....)

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

<!doctype html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Document</title>
 <style>
 div {
 width: 200px;
 height: 200px;
 background: red;
 }
 </style>
 <script>
 window.onload = function () {
  var oBox = document.getElementById("box");
  oBox.onmouseover = function(){
//  animate( this, { "width" : 500, "height" : 500 }, 10 );
  animate( this, { "width" : 500, "height" : 400 }, 10 );
  }

  function animate(obj, attr, speed) {
  clearInterval(obj.timer);
  var cur = 0;
  obj.timer = setInterval(function () {
   for ( var key in attr ) {
   if (key == 'opacity') {
    cur = css(obj, 'opacity') * 100;
   } else {
    cur = parseInt(css(obj, key));
   }
   var target = attr[key];
   if (cur == target) {
    clearInterval(obj.timer);
   } else {
    if (key == 'opacity') {
    obj.style.opacity = ( cur + speed ) / 100;
    obj.style.filter = "alpha(opacity:" + (cur + speed) + ")";
    } else {
    obj.style[key] = cur + speed + "px";
    }
   }
   }
  }, 30);
  }

  function css(obj, attr) {
  if (obj.currentStyle) {
   return obj.currentStyle[attr];
  } else {
   return getComputedStyle(obj, false)[attr];
  }
  }
 }
 </script>
</head>
<body>
 <div id="box"></div>
</body>
</html>

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

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

变化步长一样( 10 )

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

目标( width: 500, height : 400 )

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

答案是很明显的,肯定是目标近的( height : 400 )那个先到达,然后把对象上的定时器关了,另一个目标更远的( width: 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的时候再关闭定时器,不就在同一时间,完成了同时到达目标的效果吗?

修改后的代码如下:

<!doctype html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Document</title>
 <style>
 div {
 width: 200px;
 height: 200px;
 background: red;
 }
 </style>
 <script>
 window.onload = function () {
  var oBox = document.getElementById("box");
  oBox.onmouseover = function(){
  animate( this, { "width" : 500, "height" : 400 }, 10 );
  }

  function animate(obj, attr, speed) {
  clearInterval(obj.timer);
  var cur = 0;
  obj.timer = setInterval(function () {
   var bFlag = true;
   for ( var key in attr ) {
   if (key == 'opacity') {
    cur = css(obj, 'opacity') * 100;
   } else {
    cur = parseInt(css(obj, key));
   }
   var target = attr[key];
   if (cur != target) {
    bFlag = false;
    if (key == 'opacity') {
    obj.style.opacity = ( cur + speed ) / 100;
    obj.style.filter = "alpha(opacity:" + (cur + speed) + ")";
    } else {
    obj.style[key] = cur + speed + "px";
    }
   }
   }
   if ( bFlag ) {
   clearInterval( obj.timer );
   }
  }, 30);
  }

  function css(obj, attr) {
  if (obj.currentStyle) {
   return obj.currentStyle[attr];
  } else {
   return getComputedStyle(obj, false)[attr];
  }
  }
 }
 </script>
</head>
<body>
 <div id="box"></div>
</body>
</html>

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

三、顺序运动

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

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


animate( this, { 'height' : 500 }, 10 );

} );
}

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

修改后的完整代码:

<!DOCTYPE html>
<html>
<head lang="en">
 <meta charset="UTF-8">
 <title>通用的匀速运动框架 - by ghostwu</title>
 <style>
 div {
  width: 200px;
  height: 200px;
  background: red;
 }
 </style>
 <script>
 window.onload = function () {
  var oBox = document.getElementById("box");
  oBox.onmouseover = function(){
  //回调函数: 把函数当做参数传递给另一个函数
  animate( this, { 'width' : 500 }, 10, function(){
   animate( this, { 'height' : 500 }, 10 );
  } );
  }

  function animate(obj, attr, speed, fn ) {

  clearInterval(obj.timer);
  var cur = 0;
  obj.timer = setInterval(function () {
   var bFlag = true;
   for (var key in attr) {
   if (key == 'opacity') {
    cur = css(obj, 'opacity') * 100;
   } else {
    cur = parseInt(css(obj, key));
   }
   var target = attr[key];
   if (cur != target) {
    bFlag = false;
    if (key == 'opacity') {
    obj.style.opacity = ( cur + speed ) / 100;
    obj.style.filter = "alpha(opacity:" + (cur + speed) + ")";
    } else {
    obj.style[key] = cur + speed + "px";
    }
   }
   }

   if (bFlag) {
   clearInterval(obj.timer);
   fn && fn.call( obj );
   }
  }, 30);
  }

  function css(obj, attr) {
  if (obj.currentStyle) {
   return obj.currentStyle[attr];
  } else {
   return getComputedStyle(obj, false)[attr];
  }
  }
 }
 </script>
</head>
<body>
<div id="box"></div>
</body>
</html>

以上这篇打造通用的匀速运动框架(实例讲解)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
js活用事件触发对象动作
Aug 10 Javascript
JS 用6N±1法求素数 实例教程
Oct 20 Javascript
网站页面自动跳转实现方法PHP、JSP(上)
Aug 01 Javascript
事件模型在各浏览器中存在差异
Oct 20 Javascript
jquery 学习之二 属性(html()与html(val))
Nov 25 Javascript
javascript中substr,substring,slice.splice的区别说明
Nov 25 Javascript
Jquery如何实现点击时高亮显示代码
Jan 22 Javascript
四种参数传递的形式——URL,超链接,js,form表单
Jul 24 Javascript
js学使用setTimeout实现轮循动画
Jul 17 Javascript
在 Angular-cli 中使用 simple-mock 实现前端开发 API Mock 接口数据模拟功能的方法
Nov 28 Javascript
小程序显示弹窗时禁止下层的内容滚动实现方法
Mar 20 Javascript
javascript 函数的暂停和恢复实例详解
Apr 25 Javascript
封装运动框架实战左右与上下滑动的焦点轮播图(实例)
Oct 17 #Javascript
Vue中封装input组件的实例详解
Oct 17 #Javascript
js获取文件里面的所有文件名(实例)
Oct 17 #Javascript
Vue中之nextTick函数源码分析详解
Oct 17 #Javascript
vue mint-ui 实现省市区街道4级联动示例(仿淘宝京东收货地址4级联动)
Oct 16 #Javascript
jquery一键控制checkbox全选、反选或全不选
Oct 16 #jQuery
Vue2.0父子组件传递函数的教程详解
Oct 16 #Javascript
You might like
在smarty中调用php内置函数的方法
2013/02/07 PHP
鸡肋的PHP单例模式应用详解
2013/06/03 PHP
基于PHP开发中的安全防范知识详解
2013/06/06 PHP
解析wamp5下虚拟机配置文档
2013/06/27 PHP
php实现用于计算执行时间的类实例
2015/04/18 PHP
PHP抽奖算法程序代码分享
2015/10/08 PHP
thinkphp3.2.3 分页代码分享
2016/07/28 PHP
Nginx下ThinkPHP5的配置方法详解
2017/08/01 PHP
PHP获取数组中指定的一列实例
2017/12/27 PHP
imagettftext() 失效,不起作用
2021/03/09 PHP
firefox和IE系列的相关区别整理 以备后用
2009/12/28 Javascript
DOM2非标准但却支持很好的几个属性小结
2012/01/21 Javascript
解决遍历时Array.indexOf产生的性能问题
2012/07/03 Javascript
javascript标签在页面中的位置探讨
2013/04/11 Javascript
js中 关于undefined和null的区别介绍
2013/04/16 Javascript
jquery实现表格本地排序的方法
2015/03/11 Javascript
javascript实现随时变化着的背景颜色
2015/04/02 Javascript
js+CSS实现模拟华丽的select控件下拉菜单效果
2015/09/01 Javascript
正则表达式,替换所有HTML标签的简单实例
2016/11/28 Javascript
快速入门Vue
2016/12/19 Javascript
使用jQuery实现两个div中按钮互换位置的实例代码
2017/09/21 jQuery
JS实现点击下拉菜单把选择的内容同步到input输入框内的实例
2018/01/23 Javascript
[01:06]DOTA2小知识课堂 Ep.01 TP出门不要忘记帮队友灌瓶哦
2019/12/05 DOTA
Python sys.path详细介绍
2013/10/17 Python
python的urllib模块显示下载进度示例
2014/01/17 Python
用Python编写简单的定时器的方法
2015/05/02 Python
Python GUI布局尺寸适配方法
2018/10/11 Python
解决PyCharm的Python.exe已经停止工作的问题
2018/11/29 Python
tensorflow2.0教程之Keras快速入门
2021/02/20 Python
浅谈CSS3特性查询(Feature Query: @supports)功能简介
2017/07/31 HTML / CSS
网络工程与软件技术毕业生自荐信
2013/09/24 职场文书
岗位职责范本大全
2015/02/26 职场文书
纪检监察立案决定书
2015/06/24 职场文书
初中生物教学随笔
2015/08/15 职场文书
CSS的class与id常用的命名规则
2021/05/18 HTML / CSS
MySQL数据库安装方法与图形化管理工具介绍
2022/05/30 MySQL