你的浏览器不支持canvas

做你害怕做的事情,然后你会发现,不过如此。

《智能社:JavaScript教程——从入门到精通》第15~19集笔记 运动

时间: 作者: 黄运鑫

本文章属原创文章,未经作者许可,禁止转载,复制,下载,以及用作商业用途。原作者保留所有解释权。


笔记目录

  1. 《智能社:JavaScript教程——从入门到精通》第1~5集笔记 事件
  2. 《智能社:JavaScript教程——从入门到精通》第6~10集笔记
  3. 《智能社:JavaScript教程——从入门到精通》第11~14集笔记 DOM操作和表格
  4. 《智能社:JavaScript教程——从入门到精通》第15~19集笔记 运动
  5. 《智能社:JavaScript教程——从入门到精通》第20~21集笔记 鼠标键盘事件
  6. 《智能社:JavaScript教程——从入门到精通》第22~23集笔记 事件高级应用
  7. 《智能社:JavaScript教程——从入门到精通》第24~25集笔记 Ajax
  8. 《智能社:JavaScript教程——从入门到精通》第26~29集笔记 面向对象
  9. 《智能社:JavaScript教程——从入门到精通》第30~31集笔记 坐标和cookie
  10. 《智能社:JavaScript教程——从入门到精通》第32集笔记 JS正则表达式
  • 本文为原创,转载请注明:https://blog.xinpapa.com/2017/12/12/zhinengshe15-19/

详细内容

1.运动基础

  • 让div动起来
  • 速度——物体运动的快慢
  • 运动中的bug
    • 不会停止
    • 速度取某些值会无法停止
    • 到达位置后再点击还会运动
    • 重复点击速度加快
  • 匀速运动
    • 速度不变

2.运动框架

  • 例子1(网页的“分享到”侧边栏)如图:
    image
    代码如下:
    #div1{
      width: 150px;
      height: 200px;
      background: #B3D4FC;
      position: absolute;
      left: -150px;
    }
    #div1 span{
      position: absolute;
      width: 20px;
      height: 60px;
      line-height: 20px;
      background: gray;
      right: -20px;
      top: 70px;
    }
    
      <body>
          <div id="div1">
              <span>分享到</span>
          </div>
      </body>
    
    window.onload = function () {
      var oDiv = document.getElementById("div1");
      oDiv.onmouseover = function () {
          startMove(10, 0);
      };
      oDiv.onmouseout = function () {
          startMove(-10, -150);
      };
    };
    var timer = null;
    function startMove(speed, iTarget) {
      var oDiv = document.getElementById("div1");
      //先关闭定时器再开启,防止开启多个定时器
      clearInterval(timer);
      timer = setInterval(function () {
          if (oDiv.offsetLeft == iTarget) {
              clearInterval(timer);
          } else {
              oDiv.style.left = oDiv.offsetLeft + speed + "px";
          }
      }, 30);
    };
    
  • 例子2(淡入淡出的图片)
    代码如下:
    #div1{
      width: 200px;
      height: 200px;
      background: red;
      filter: alpha(opacity:30);
      opacity: 0.3;
    }
    
      <body>
          <div id="div1"></div>
      </body>
    
    var alpha = 30;//alpha变量用于改变透明度
    var timer = null;
    function startMove(iTarget) {
      var oDiv = document.getElementById("div1");
      clearInterval(timer);//先关闭,避免开启多个定时器
      timer = setInterval(function () {
          var speed = 0;
          if (alpha < iTarget) {
              speed = 10;
          } else {
              speed = -10;
          }
          if (alpha == iTarget) {
              clearInterval(timer);
          } else {
              alpha += speed;
              oDiv.style.filter = "alpha(opacity:" + alpha + ")";
              oDiv.style.opacity = alpha / 100;//兼容火狐和chorme
          }
      }, 30);
    };
    window.onload = function () {
      var oDiv = document.getElementById("div1");
      oDiv.onmousemove = function () {
          startMove(100);
      };
      oDiv.onmouseout = function () {
          startMove(30);
      };
    };
    

3.缓冲运动

  • 逐渐变慢,最后停止
  • 距离越远速度越大
    • 速度由距离决定
    • 速度=(目标值-当前值)/缩放系数
  • 例子:缓冲菜单
    • bug:速度取整
    • 跟随页面滚动的缓冲侧边栏
      • 潜在问题:目标值不是整数时
  • 代码如下(页面右侧悬浮框):
      #div1{
          width: 100px;
          height: 150px;
          background: red;
          position: absolute;
          right: 0;
          bottom: 0;
      }
    
      <body style="height: 2000px;">
          <div id="div1"></div>
      </body>
    
    //元素滚动时执行
    window.onscroll = function () {
      var oDiv = document.getElementById("div1");
      var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
      startMove(parseInt((document.documentElement.clientHeight - oDiv.offsetHeight) / 2 + scrollTop));
    };
    var timer = null;
    function startMove(iTarget) {
      var oDiv = document.getElementById("div1");
      clearInterval(timer);
      timer = setInterval(function () {
          var speed = (iTarget - oDiv.offsetTop) / 6;
          speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
          if (oDiv.offsetTop == iTarget) {
              clearInterval(timer);
          } else {
              oDiv.style.top = oDiv.offsetTop + speed + "px";
          }
      }, 30);
    };
    

4.多物体运动框架

  • 例子:多个div,鼠标移入变宽
    • 单定时器,存在问题
    • 每个div一个定时器
  • 代码如下:
    div{
      width: 100px;
      height: 50px;
      background: red;
      margin: 10px;
    }
    
      <body>
          <div></div>
          <div></div>
          <div></div>
      </body>
    
    window.onload = function () {
      var aDiv = document.getElementsByTagName("div");
      for (var i = 0; i < aDiv.length; i++) {
          aDiv[i].timer = null;//每一个div都加一个定时器
          aDiv[i].onmouseover = function () {
              startMove(this, 400);
          };
          aDiv[i].onmouseout = function () {
              startMove(this, 100);
          };
      }
    };
    function startMove(obj, iTarget) {
      clearInterval(obj.timer);
      obj.timer = setInterval(function () {
          var speed = (iTarget - obj.offsetWidth) / 6;
          speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
          if (obj.offsetWidth == iTarget) {
              clearInterval(obj.timer);
          } else {
              obj.style.width = obj.offsetWidth + speed + "px";
          }
      }, 30);
    };
    
  • 多物体运动框架
    • 定时器作为物体的属性
    • 参数的传递:物体:目标值
    • 例子:多个div淡入淡出
      • 所有东西都不能公用
      • 属性与运动对象绑定:速度、其他属性值(如透明度等)
  • 代码如下:
    div{
      width: 200px;
      height: 200px;
      margin: 20px;
      float: left;
      background: red;
      filter: alpha(opacity:30);
      opacity: 0.3;
    }
    
      <body>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
      </body>
    
    window.onload = function () {
      var aDiv = document.getElementsByTagName("div");
      for (var i = 0; i < aDiv.length; i++) {
          aDiv[i].alpha = 30;//给每个div增加一个alpha属性
          aDiv[i].onmouseover = function () {
              startMove(this, 100);
          };
          aDiv[i].onmouseout = function () {
              startMove(this, 30);
          };
      }
    };
    //多物体运动框架的方法
    function startMove(obj, iTarget) {
      clearInterval(obj.timer);
      obj.timer = setInterval(function () {
          var speed = (iTarget - obj.alpha) / 6;
          speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
          if (obj.alpha == iTarget) {
              clearInterval(obj.timer);
          } else {
              obj.alpha += speed;
              obj.style.filter = "alpha(opacity:" + obj.alpha + ")";
              obj.style.opacity = obj.alpha / 100;
          }
      }, 30);
    };
    

5.任意值运动框架

  • offset属性的bug
    • offset时,让有边框的div变宽会出现bug
    • 解决方法是用currentStyle代替offset
  • 扩展运动矿井唉
    • 运动属性作为参数
    • 封装opacity
  • 代码如下:
    div{
      width: 200px;
      height: 200px;
      margin: 20px;
      float: left;
      background: red;
      border: 10px black solid;
      font-size: 16px;
      filter: alpha(opacity:30);
      opacity: 0.3;
    }
    
      <body>
          <div id="div1">变宽</div>
          <div id="div2">变高</div>
          <div id="div3">变字体大小</div>
          <div id="div4">变边框宽度</div>
          <div id="div5">变透明度</div>
      </body>
    
    window.onload = function () {
      var oDiv1 = document.getElementById("div1");
      var oDiv2 = document.getElementById("div2");
      var oDiv3 = document.getElementById("div3");
      var oDiv4 = document.getElementById("div4");
      var oDiv5 = document.getElementById("div5");
      oDiv1.onmouseover = function () {
          startMove(this, "height", 400);
      };
      oDiv1.onmouseout = function () {
          startMove(this, "height", 200);
      };
      oDiv2.onmouseover = function () {
          startMove(this, "width", 400);
      };
      oDiv2.onmouseout = function () {
          startMove(this, "width", 200);
      };
      oDiv3.onmouseover = function () {
          startMove(this, "font-size", 30);
      };
      oDiv3.onmouseout = function () {
          startMove(this, "font-size", 16);
      };
      oDiv4.onmouseover = function () {
          startMove(this, "borderWidth", 50);
      };
      oDiv4.onmouseout = function () {
          startMove(this, "borderWidth", 10);
      };
      oDiv5.onmouseover = function () {
          startMove(this, "opacity", 100);
      };
      oDiv5.onmouseout = function () {
          startMove(this, "opacity", 30);
      };
    };
    //多物体运动框架的方法
    function startMove(obj, attr, iTarget) {
      clearInterval(obj.timer);
      obj.timer = setInterval(function () {
          var cur = 0;
          if (attr == "opacity") {//判断改变的是透明度还是其他属性
              //round为四舍五入取整,解决计算失去精度的问题(比如0.07*100)
              cur = Math.round(parseFloat(getStyle(obj, attr)) * 100);
          } else {
              cur = parseInt(getStyle(obj, attr));
          }
          var speed = (iTarget - cur) / 6;
          //三目运算用于判断是要向上取整还是向下取整
          speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
          if (cur == iTarget) {//如果是true,则停止定时器
              clearInterval(obj.timer);
          } else {
              if (attr == "opacity") {//判断改变的是透明度还是其他属性
                  obj.style.filter = "alpha(opacity:" + (cur + speed) + ")";
                  obj.style.opacity = (cur + speed) / 100;//给火狐和chrome用
              } else {
                  obj.style[attr] = cur + speed + "px";
              }
          }
      }, 30);
    };
    function getStyle(obj, name) {
      if (obj.currentStyle) {
          return obj.currentStyle[name];
      } else {
          return getComputedStyle(obj, null)[name];
      }
    };
    

6.仿Flash图片展示1

  • div动起来

    偷懒了,没写

7.链式运动框架

  • 用到回调函数
    • 运动停止时,执行函数,开始下一次运动
  • 例子代码如下:
    #div1{
      width: 100px;
      height: 100px;
      background: red;
      filter:alpha(opacity:30);
      opacity: 0.3;
    }
    
      <body>
          <div id="div1"></div>
      </body>
    
    window.onload = function () {
      var oDiv = document.getElementById("div1");
      oDiv.onmouseover = function () {
          startMove(oDiv, "width", 400, function () {
              startMove(oDiv, "height", 400, function () {
                  startMove(oDiv, "opacity", 100);
              });
          });
      };
      oDiv.onmouseout = function () {
          startMove(oDiv, "opacity", 30, function () {
              startMove(oDiv, "height", 100, function () {
                  startMove(oDiv, "width", 100);
              });
          });
      };
    };
    //多物体运动框架的方法
    function startMove(obj, attr, iTarget, fnEnd) {
      clearInterval(obj.timer);
      obj.timer = setInterval(function () {
          var cur = 0;
          if (attr == "opacity") {//判断改变的是透明度还是其他属性
              //round为四舍五入取整,解决计算失去精度的问题(比如0.07*100)
              cur = Math.round(parseFloat(getStyle(obj, attr)) * 100);
          } else {
              cur = parseInt(getStyle(obj, attr));
          }
          var speed = (iTarget - cur) / 6;
          //三目运算用于判断是要向上取整还是向下取整
          speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
          if (cur == iTarget) {//如果是true,则停止定时器
              clearInterval(obj.timer);
              if (fnEnd) {
                  fnEnd();//回调函数
              }
          } else {
              if (attr == "opacity") {//判断改变的是透明度还是其他属性
                  obj.style.filter = "alpha(opacity:" + (cur + speed) + ")";
                  obj.style.opacity = (cur + speed) / 100;//给火狐和chrome用
              } else {
                  obj.style[attr] = cur + speed + "px";
              }
          }
      }, 30);
    };
    function getStyle(obj, name) {
      if (obj.currentStyle) {
          return obj.currentStyle[name];
      } else {
          return getComputedStyle(obj, null)[name];
      }
    };
    

8.完美运动框架

  • 多个值同时变化
    • setStyle同时设置多个属性
      • 参数传递:json的使用、for in遍历属性
    • 运动到运动框架
    • 检测运动停止
      • 标志变量
  • 例子代码如下(伸缩的同时淡入淡出的菜单):
    #div1{
      width: 100px;
      height: 100px;
      background: red;
      filter: alpha(opacity:30);
      opacity: 0.3;
    }
    
      <body>
          <input id="btn1" type="button" value="运动" />
          <div id="div1"></div>
      </body>
    
    window.onload = function () {
      var oBtn = document.getElementById("btn1");
      var oDiv = document.getElementById("div1");
      oBtn.onclick = function () {
          startMove(oDiv, {width: 103, height: 300, opacity: 100});
      };
    };
    //完美运动框架的方法
    function startMove(obj, json, fnEnd) {
      clearInterval(obj.timer);
      obj.timer = setInterval(function () {
          var stop = true;//假设所有的值都已经到了
          for (var attr in json) {
              var cur = 0;
              if (attr == "opacity") {//判断改变的是透明度还是其他属性
                  //round为四舍五入取整,解决计算失去精度的问题(比如0.07*100)
                  cur = Math.round(parseFloat(getStyle(obj, attr)) * 100);
              } else {
                  cur = parseInt(getStyle(obj, attr));
              }
              var speed = (json[attr] - cur) / 6;
              //三目运算用于判断是要向上取整还是向下取整
              speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
              //如果有任何一个运动没完成,则stop=false,不关闭定时器
              if (cur != json[attr]) {
                  stop = false;
              }
              if (attr == "opacity") {//判断改变的是透明度还是其他属性
                  obj.style.filter = "alpha(opacity:" + (cur + speed) + ")";
                  obj.style.opacity = (cur + speed) / 100;//给火狐和chrome用
              } else {
                  obj.style[attr] = cur + speed + "px";
              }
          }
          if (stop) {//如果是true则所有运动都完成
              clearInterval(obj.timer);
              if (fnEnd) {
                  fnEnd();//回调函数
              }
          }
      }, 30);
    };
    

9.运动框架总结

  • 运动框架演变过程
    • startMove(iTarget):运动框架
    • startMove(obj,iTarget):多物体运动框架
    • startMove(obj,attr,iTarget):任意值运动框架
    • startMove(obj,attr,iTarget,fn):链式运动框架
    • startMove(obj,json,f):完美运动框架
  • 例子(微博发布新信息效果):
    #ul1{
      margin: 10px auto;
      padding: 0;
      width: 400px;
      height: 400px;
      border: 1px black solid;
      overflow: hidden;
    }
    #ul1 li{
      border-bottom: 1px #999 dashed;
      list-style: none;
      overflow: hidden;
      filter: alpha(opacity:0);
      opacity: 0;
    }
    
      <body>
          <textarea id="txt1" rows="4" cols="40"></textarea>
          <input id="btn1" type="button" value="发布" />
          <ul id="ul1">
          </ul>
      </body>
    
    window.onload = function () {
      var oBtn = document.getElementById("btn1");
      var oUl = document.getElementById("ul1");
      var oTxt = document.getElementById("txt1");
      oBtn.onclick = function () {
          var oLi = document.createElement("li");
          oLi.innerHTML = oTxt.value;
          oTxt.value = "";
          if (oUl.children.length > 0) {
              oUl.insertBefore(oLi, oUl.children[0]);
          } else {
              oUl.appendChild(oLi);
          }
          //运动
          var iHeight = oLi.offsetHeight;
          oLi.style.height = "0";
          startMove(oLi, {height: iHeight}, function () {
              startMove(oLi, {opacity: 100})
          });
      };
    };
    //完美运动框架的方法
    function startMove(obj, json, fnEnd) {
      clearInterval(obj.timer);
      obj.timer = setInterval(function () {
          var stop = true;//假设所有的值都已经到了
          for (var attr in json) {
              var cur = 0;
              if (attr == "opacity") {//判断改变的是透明度还是其他属性
                  //round为四舍五入取整,解决计算失去精度的问题(比如0.07*100)
                  cur = Math.round(parseFloat(getStyle(obj, attr)) * 100);
              } else {
                  cur = parseInt(getStyle(obj, attr));
              }
              var speed = (json[attr] - cur) / 6;
              //三目运算用于判断是要向上取整还是向下取整
              speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
              //如果有任何一个运动没完成,则stop=false,不关闭定时器
              if (cur != json[attr]) {
                  stop = false;
              }
              if (attr == "opacity") {//判断改变的是透明度还是其他属性
                  obj.style.filter = "alpha(opacity:" + (cur + speed) + ")";
                  obj.style.opacity = (cur + speed) / 100;//给火狐和chrome用
              } else {
                  obj.style[attr] = cur + speed + "px";
              }
          }
          if (stop) {//如果是true则所有运动都完成
              clearInterval(obj.timer);
              if (fnEnd) {
                  fnEnd();//回调函数
              }
          }
      }, 30);
    };
    //得到样式属性的方法
    function getStyle(obj, name) {
      if (obj.currentStyle) {
          return obj.currentStyle[name];//IE
      } else {//其他浏览器
          return getComputedStyle(obj, null)[name];
      }
    }
    

对于本文内容有问题或建议的小伙伴,欢迎在文章底部留言交流讨论。