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


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 相关文章推荐
Mootools 1.2教程 正则表达式
Sep 15 Javascript
javascript多种数据类型表格排序代码分析
Sep 11 Javascript
jQuery实现点击后标记当前菜单位置(背景高亮菜单)效果
Aug 22 Javascript
AngularJs实现ng1.3+表单验证
Dec 10 Javascript
使用Sticky组件实现带sticky效果的tab导航和滚动导航的方法
Mar 22 Javascript
javascript和jquery实现用户登录验证
May 04 Javascript
jquery实现企业定位式导航效果
Jan 01 jQuery
vue实现引入本地json的方法分析
Jul 12 Javascript
JavaScript实现横版菜单栏
Mar 17 Javascript
解决vue动态下拉菜单 有数据未反应的问题
Aug 06 Javascript
JavaScript实现单点登录的示例
Sep 23 Javascript
Ant Design Vue table中列超长显示...并加提示语的实例
Oct 31 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
索尼ICF-SW100收音机评测
2021/03/02 无线电
编写自己的php扩展函数
2006/10/09 PHP
PHP使用PDO访问oracle数据库的步骤详解
2017/09/29 PHP
JavaScript初学者应注意的七个细节详细介绍
2012/12/27 Javascript
表格奇偶行设置不同颜色的核心JS代码
2013/12/24 Javascript
JS实现响应鼠标点击动画渐变弹出层效果代码
2016/03/25 Javascript
js中 计算两个日期间的工作日的简单实例
2016/08/08 Javascript
jQuery中弹出iframe内嵌页面元素到父页面并全屏化的实例代码
2016/12/27 Javascript
详解利用jsx写vue组件的方法示例
2017/07/17 Javascript
Vue2.0用户权限控制解决方案
2017/11/29 Javascript
微信小程序项目实践之九宫格实现及item跳转功能
2018/07/19 Javascript
基于Vue全局组件与局部组件的区别说明
2020/08/11 Javascript
[36:05]DOTA2亚洲邀请赛 3.31 小组赛 A组 Liquid vs Optic
2018/04/01 DOTA
python实现TCP服务器端与客户端的方法详解
2015/04/30 Python
python安装与使用redis的方法
2016/04/19 Python
Python实现嵌套列表去重方法示例
2017/12/28 Python
Python内置模块hashlib、hmac与uuid用法分析
2018/02/12 Python
详解python执行shell脚本创建用户及相关操作
2019/04/11 Python
在Python中预先初始化列表内容和长度的实现
2019/11/28 Python
如何基于python操作json文件获取内容
2019/12/24 Python
python3中sorted函数里cmp参数改变详解
2020/03/12 Python
自定义Django_rest_framework_jwt登陆错误返回的解决
2020/10/18 Python
Free People中国官网:波西米亚风格女装服饰
2016/08/30 全球购物
MYSQL基础面试题
2012/05/13 面试题
自我评价200字分享
2013/12/17 职场文书
舞蹈教师自荐信
2014/01/27 职场文书
社区八一活动方案
2014/02/03 职场文书
一年级学生评语大全
2014/04/21 职场文书
先进班集体事迹材料
2014/12/25 职场文书
财务负责人岗位职责
2015/02/03 职场文书
民主评议党员个人总结
2015/02/13 职场文书
工作推荐信模板
2015/03/25 职场文书
单位介绍信格式范文
2015/05/04 职场文书
亮剑观后感600字
2015/06/05 职场文书
假如给我三天光明读书笔记
2015/06/26 职场文书
拥有这5个特征人,“命”都不会太差
2019/08/16 职场文书