成都IT培训学校

如何用js优雅地对ta说“自己动”——匀速运动

2016-09-07 15:53 作者:熊郅峰 来源:简书 浏览: 我要评论(条) 字号:

摘要:js中匀速运动的基本原理: 用定时器不断的改变元素的某一属性,从而达到动态效果 由于动图实在是太麻烦(好吧,是我懒 _`),建议大家下载源码,方便同步演示 ?戳此下载源码 提纲 简单的从左至右运动 终止运动 运动的速度控制 处理bug:由速度引起的无法终止



  js中匀速运动的基本原理:
 
  用定时器不断的改变元素的某一属性,从而达到动态效果
 
  由于动图实在是太麻烦(好吧,是我懒 '_>`),建议大家下载源码,方便同步演示
 
  ?戳此下载源码
 
  提纲
 
  简单的从左至右运动
 
  终止运动
 
  运动的速度控制
 
  处理bug:由速度引起的无法终止运动
 
  处理bug:达到目标后点击按钮仍向前运动
 
  处理bug:多次点击按钮会使速度变快
 
  demo:div的鼠标移入滑出运动
 
  demo:透明度运动
 
  简单的从左至右运动:
 
  <!DOCTYPE html>
 
  <html lang="en">
 
  <head>
 
  <meta charset="UTF-8">
 
  <title>Document</title>
 
  <style type="text/css">
 
  #div1{
 
  width: 150px;
 
  height: 80px;
 
  background-color: #2470B4;
 
  position: absolute;
 
  top: 50px;
 
  left: 100px;
 
  }
 
  </style>
 
  <script type="text/javascript">
 
  function startMove() {
 
  var oDiv1 = document.getElementById("div1");
 
  setInterval(function () {
 
  //每30毫秒div1的left属性增加7
 
  oDiv1.style.left = oDiv1.offsetLeft + 7 + "px";
 
  }, 30);
 
  }
 
  </script>
 
  </head>
 
  <body>
 
  <input type="button" value="开始运动" onclick="startMove();">
 
  <div id="div1"></div>
 
  </body>
 
  </html>
 
  这是最简单的运动了,点击按钮,蓝色div会一直向右走…
 
  …一直走到天荒地老
 
  由于我们没有设置终止,div会一直向右移动,现在我们来想办法让它停下来
 
  终止运动
 
  我们是通过定时器让div动起来的,想让它停下来,就得关掉定时器:
 
  <script type="text/javascript">
 
  var timer = null;
 
  function startMove() {
 
  var oDiv1 = document.getElementById("div1");
 
  timer = setInterval(function () {
 
  //让div1移动到500px停下来
 
  if(oDiv1.offsetLeft == 500) clearInterval(timer);
 
  //每30毫秒div1的left属性增加7
 
  oDiv1.style.left = oDiv1.offsetLeft + 10 + "px";
 
  }, 30);
 
  }
 
  </script>
 
  用一个变量 timer 来存储定时器,方便关闭,在每次定时器启动的时候先判断是否达到终止条件
 
  如果达到了就用 clearInterval(timer);关闭定时器,停止运动
 
  运动的速度控制
 
  由之前的代码可以看出,真正控制运动的是
 
  `oDiv1.style.left = oDiv1.offsetLeft + 10 + "px";`
 
  而这个运动速度是由增量10来决定的,增量越大,运动越快,反之亦然
 
  为了方便变更速度,我们可以用一个变量 speed 来保存增量:
 
  timer = setInterval(function () {
 
  var speed = 7;
 
  if(oDiv1.offsetLeft == 500) clearInterval(timer);
 
  oDiv1.style.left = oDiv1.offsetLeft + speed + "px";
 
  }, 30);
 
  这样改变speed的值就可以改变速度了,这里我们改成了7
 
  bug:由速度引起的无法终止运动
 
  速度改为7之后出现了一个bug:div达到了终止条件依然还在移动
 
  原因很明显,speed为7即增量为7,而我们设置的初始left为100
 
  也就是说,div1的offsetLeft永远也不会等于500,也就无法停止定时器停下来了
 
  所以我们应该修改下终止条件:
 
  改为oDiv1.offsetLeft >= 500,这样就能保证不论speed能否整除500,div都能停下来了
 
  到目前为止,我们的div已经能动,能停了,但是依然漏洞百出
 
  bug:达到目标后点击按钮仍向前运动
 
  大家可以试下,第一次点击按钮可以让div动起来,停止后,再次点击按钮,div会蹿一下,点一下蹿一下,点一下蹿一下…
 
  这是因为setInterval()这个函数跟do{…}while()有点像,do while是先执行一遍再判断,而前者是先运行一遍,再延时,运行时虽然达到了终止边界要停止定时器,但是这一遍是要运行完的,所以会向前走一个距离增量
 
  解决办法非常简单,既然达到了终止条件,就应该不运行后面的代码了,把后面的代码用else包起来就行了:
 
  timer = setInterval(function () {
 
  var speed = 7;
 
  if(oDiv1.offsetLeft >= 500){
 
  clearInterval(timer);
 
  } else {
 
  oDiv1.style.left = oDiv1.offsetLeft + speed + "px";
 
  oP.innerHTML = oDiv1.offsetLeft + "px";
 
  }
 
  }, 30);
 
  这样就只有当oDiv1.offsetLeft < 500时才会执行后面的代码
 
  bug:多次点击按钮会使速度变快
 
  最后这个小bug是非常常见的,先说说问题的原因吧,这是因为每次点击按钮都会开启一个定时器,假如要给定时器30毫秒的增量是10,点三次开启三个定时器的话30毫秒的增量就成了30,所以就越来越快
 
  解决办法也十分有代表性,在每次点击按钮时先关闭定时器,再开启,这样就能保证只有一个定时器在运行:
 
  clearInterval(timer);
 
  timer = setInterval(function () {
 
  var speed = 7;
 
  if(oDiv1.offsetLeft >= 500){
 
  clearInterval(timer);
 
  } else {
 
  oDiv1.style.left = oDiv1.offsetLeft + speed + "px";
 
  oP.innerHTML = oDiv1.offsetLeft + "px";
 
  }
 
  }, 30);
 
  demo:div的鼠标移入滑出运动
 
  大家一定见过这种效果:一个小div悬浮在屏幕的一侧,鼠标移入时,小div连着一个大div一起滑出,鼠标移出时又收回去,只剩小div继续悬浮在屏幕一侧。
 
  有了之前的经验,思路变得非常清晰:
 
  把大div定位到屏幕外边隐藏起来
 
  鼠标移入时:两个div移出,露出大div
 
  鼠标移出时:两个div收回,只剩小div
 
  html代码:
 
  <body>
 
  <div id="div1">
 
  <div id="div2"></div>
 
  </div>
 
  </body>
 
  CSS代码:
 
  #div1{
 
  width: 200px;
 
  height: 400px;
 
  border: 1px solid #2470B4;
 
  position: absolute;
 
  top: 100px;
 
  left: -200px;
 
  }
 
  #div2{
 
  width: 30px;
 
  height: 100px;
 
  background-color: #2470B4;
 
  position: absolute;
 
  top: 150px;
 
  right: -30px;
 
  }
 
  js代码:
 
  window.onload = function () {
 
  var oDiv1 = document.getElementById("div1");
 
  var timer = null;
 
  oDiv1.onmouseover = function () {
 
  clearInterval(timer);//先清除定时器,确保只有一个定时器在运行
 
  //鼠标移入offsetLeft要增加,speed为正
 
  var speed = 10;
 
  timer = setInterval(function () {
 
  if(oDiv1.offsetLeft == 0){        //鼠标移入offsetLeft由-200变为0
 
  clearInterval(timer);
 
  } else {
 
  oDiv1.style.left = oDiv1.offsetLeft + speed +"px";
 
  }
 
  }, 30)
 
  }
 
  oDiv1.onmouseout = function () {
 
  clearInterval(timer);//先清除定时器,确保只有一个定时器在运行
 
  //鼠标移入offsetLeft要减小,speed为负
 
  var speed = -10;
 
  timer = setInterval(function () {
 
  if(oDiv1.offsetLeft == -200){    //鼠标移入offsetLeft由0变为-200
 
  clearInterval(timer);
 
  } else {
 
  oDiv1.style.left = oDiv1.offsetLeft + speed +"px";
 
  }
 
  }, 30)
 
  }
 
  }
 
  实现效果虽然十分简单,但是写出来的代码重复的地方太多了,臃肿难看,不够优雅,我们想办法来改进一下
 
  大家可以看出来,这里onmouseover和onmouseout调用的两个匿名函数几乎一模一样,只有两个关键的值不同——移动终点和速度的正负,而速度的正负可以有移动终点来判断,所以我们不妨重新定义一个函数toggleShow(target),把这两个值提取出来,统一成一个参数传进去,这样就可以把两个函数合二为一了:
 
  window.onload = function () {
 
  var oDiv1 = document.getElementById("div1");
 
  var timer = null;
 
  oDiv1.onmouseover = function () {
 
  toggleShow(0);
 
  };
 
  oDiv1.onmouseout = function () {
 
  toggleShow(-200);
 
  };
 
  function toggleShow(target) {
 
  clearInterval(timer);
 
  var speed = 0;
 
  //根据target的位置来判断速度的正负
 
  speed = target - oDiv1.offsetLeft > 0 ? 10 : -10;
 
  timer = setInterval(function () {
 
  if(oDiv1.offsetLeft == target){
 
  clearInterval(timer);
 
  } else {
 
  oDiv1.style.left = oDiv1.offsetLeft + speed +"px";
 
  }
 
  }, 30)
 
  }
 
  }
 
  比较一下,是不是精简了许多:)
 
  demo:透明度运动
 
  这个效果也挺常见的,鼠标移入div变得不透明,移出再变的半透明,又叫淡入淡出。
 
  原理跟上个demo一样,只是这次改变的是透明度:
 
  设置透明度的初始值为30(0.3)
 
  鼠标移入时:透明度增加到100(1)
 
  鼠标移出时:透明度减小到30(0.3)
 
  html代码:
 
  <body>
 
  <div id="div1"></div>
 
  </body>
 
  CSS代码:
 
  #div1{
 
  width: 300px;
 
  height: 200px;
 
  background-color: #2470B4;
 
  margin: 150px auto;
 
  opacity: 0.5;
 
  filter: alpha(opacity: 30);
 
  }
 
  css中不同浏览器的设置透明度的属性不同:
 
  opacity:0.5            //for IE9, Firefox, Chrome, Opera, Safari
 
  filter:alpha(opacity = 50) //for IE6, IE7, IE8
 
  后者也可以写成:
 
  filter:alpha(opacity:50) //for IE6, IE7, IE8
 
  js代码:
 
  window.onload = function () {
 
  var oDiv1 = document.getElementById("div1");
 
  var timer = null;
 
  var alpha = 30;
 
  function toggleShow(target) {
 
  clearInterval(timer);
 
  var speed = target - alpha > 0 ? 10 : -10;
 
  timer = setInterval(function () {
 
  if(alpha == target){
 
  clearInterval(timer);
 
  } else {
 
  alpha += speed;
 
  oDiv1.style.opacity = alpha/100;
 
  oDiv1.style.filter =  "alpha(opacity: " + alpha + ")";
 
  }
 
  }, 30)
 
  }
 
  oDiv1.onmouseover = function () {
 
  toggleShow(100);
 
  }
 
  oDiv1.onmouseout = function () {
 
  toggleShow(30);
 
  }
 
  }
 
  这里用了个小技巧:
 
  由于透明度的设置方法有两种,不方便直接获取当前透明度的值,这里用了一个变量alpha来保存透明度的值,alpha的初值设为30,跟css中设置的相同,而且增量是直接作用于alpha上的,最后才让透明度等于alpha的值
 
  其他值得注意的是,参数target是0-100的数值,所以最后oDiv1.style.opacity = alpha/100;要除以100以恢复0-1的取值范围
 
  以上。
 
  
顶一下
(0)
0%
踩一下
(0)
0%
标签:
版权所有: 非特殊声明均为本站原创文章,转载请注明出处: 成都学前端开发网-web.ixueyun.com
订阅更新: 您可以通过RSS订阅我们的内容更新

当前栏目分类