title: 36-offset相关属性和匀速动画(含轮播图的实现)
publish: true
前言
JS动画的主要内容如下:
1、三大家族和一个事件对象:
2、动画(闪现/匀速/缓动)
3、冒泡/兼容/封装
offset 家族的组成
我们知道,JS动画的三大家族包括:offset/scroll/client。今天来讲一下offset,以及与其相关的匀速动画。
offset的中文是:偏移,补偿,位移。
js中有一套方便的获取元素尺寸的办法就是offset家族。offset家族包括:
offsetWidth
 
offsetHight
 
offsetLeft
 
offsetTop
 
offsetParent
 
下面分别介绍。
1、offsetWidth 和 offsetHight
offsetWidth 和 offsetHight:获取元素的宽高 + padding + border,不包括margin。如下:
这两个属性,他们绑定在了所有的节点元素上。获取元素之后,只要调用这两个属性,我们就能够获取元素节点的宽和高。
举例如下:
<!DOCTYPE html> <html> <head lang="en">     <meta charset="UTF-8">     <title></title>     <style>         div {             width: 100px;             height: 100px;             padding: 10px;             border: 10px solid #000;             margin: 100px;             background-color: pink;         }     </style> </head> <body>
  <div class="box"></div> <script>     var div1 = document.getElementsByTagName("div")[0];
      console.log(div1.offsetHeight);               console.log(typeof div1.offsetHeight);   
  </script> </body> </html>
   | 
 
2、offsetParent
offsetParent:获取当前元素的定位父元素。
举例:
<!DOCTYPE html> <html> <head lang="en">     <meta charset="UTF-8">     <title></title> </head> <body> <div class="box1" style="position: absolute;">     <div class="box2" style="position: fixed;">         <div class="box3"></div>     </div> </div> <script>
      var box3 = document.getElementsByClassName("box3")[0];
      console.log(box3.offsetParent); </script> </body> </html>
   | 
 
打印结果:

3、offsetLeft 和 offsetTop
offsetLeft:当前元素相对于其定位父元素的水平偏移量。
offsetTop:当前元素相对于其定位父元素的垂直偏移量。
备注:从父亲的 padding 开始算起,父亲的 border 不算在内。
举例:
<!DOCTYPE html> <html> <head lang="en">     <meta charset="UTF-8">     <title></title>     <style>         .box1 {             width: 300px;             height: 300px;             padding: 100px;             margin: 100px;             position: relative;             border: 100px solid #000;             background-color: pink;         }
          .box2 {             width: 100px;             height: 100px;             background-color: red;                                                }     </style> </head> <body> <div class="box1">     <div class="box2" style="left: 10px"></div> </div>
  <script>
      var box2 = document.getElementsByClassName("box2")[0];
           console.log(box2.offsetLeft);       console.log(box2.style.left);  
 
  </script>
  </body> </html>
   | 
 
在父盒子有定位的情况下,offsetLeft == style.left(去掉px之后)。注意,后者只识别行内样式。但区别不仅仅于此,下面会讲。
offsetLeft 和 style.left 区别
(1)最大区别在于:
offsetLeft 可以返回无定位父元素的偏移量。如果父元素中都没有定位,则body为准。
style.left 只能获取行内样式,如果父元素中都没有设置定位,则返回””(意思是,返回空字符串);
(2)offsetTop 返回的是数字,而 style.top 返回的是字符串,而且还带有单位:px。
比如:
 div.offsetLeft = 100; div.style.left = "100px";
 
 
  | 
 
(3)offsetLeft 和 offsetTop 只读,而 style.left 和 style.top 可读写(只读是获取值,可写是修改值)
总结:我们一般的做法是:用offsetLeft 和 offsetTop 获取值,用style.left 和 style.top 赋值(比较方便)。理由如下:
动画的种类
闪现(基本不用)
 
匀速(本文重点)
 
缓动(后续重点)
 
简单举例如下:(每间隔500ms,向右移动盒子100px)
<!DOCTYPE html> <html> <head lang="en">     <meta charset="UTF-8">     <title></title>     <style>         div {             width: 100px;             height: 100px;             background-color: pink;             position: absolute;         }     </style> </head> <body> <button>动画</button> <div class="box" style="left: 0px"></div>
  <script>     var btn = document.getElementsByTagName("button")[0];     var div = document.getElementsByTagName("div")[0];
                     
           btn.onclick = function () {                  setInterval(function () {             console.log(parseInt(div.style.left));                                       div.style.left = div.offsetLeft + 100 + 'px';
                                    }, 500);     }; </script> </body> </html>
   | 
 
效果如下:

匀速动画的封装:每间隔30ms,移动盒子10px【重要】
代码如下:
<!DOCTYPE html> <html> <head lang="en">     <meta charset="UTF-8">     <title></title>     <style>         .box1 {             margin: 0;             padding: 5px;             height: 300px;             background-color: #ddd;             position: relative;         }
          button {             margin: 5px;         }
          .box2 {             width: 100px;             height: 100px;             background-color: red;             position: absolute;             left: 195px;             top: 40px;         }
          .box3 {             width: 100px;             height: 100px;             background-color: yellow;             position: absolute;             left: 0;             top: 150px;         }     </style> </head> <body> <div class="box1">     <button>运动到 left = 200px</button>     <button>运动到 left = 400px</button>     <div class="box2"></div>     <div class="box3"></div> </div>
  <script>     var btnArr = document.getElementsByTagName("button");     var box2 = document.getElementsByClassName("box2")[0];     var box3 = document.getElementsByClassName("box3")[0];
           btnArr[0].onclick = function () {                           animate(box2, 200);         animate(box3, 200);     }
      btnArr[1].onclick = function () {         animate(box2, 400);         animate(box3, 400);     }
           function animate(ele, target) {                                    clearInterval(ele.timer);                           var speed = target > ele.offsetLeft ? 10 : -10;           ele.timer = setInterval(function () {                          var val = target - ele.offsetLeft;             ele.style.left = ele.offsetLeft + speed + "px";                                       if (Math.abs(val) < Math.abs(speed)) {                 ele.style.left = target + "px";                 clearInterval(ele.timer);             }         }, 30)     } </script> </body> </html>
   | 
 
实现的效果:

上方代码中的方法封装,可以作为一个模板步骤,要记住。其实,这个封装的方法,写成下面这样,会更严谨,更容易理解:(将if语句进行了改进)
 function animate(ele, target) {                    clearInterval(ele.timer);               var speed = target > ele.offsetLeft ? 10 : -10;       ele.timer = setInterval(function () {                  var val = target - ele.offsetLeft;
                            if (Math.abs(val) < Math.abs(speed)) {               ele.style.left = target + "px";             clearInterval(ele.timer);         } else {             ele.style.left = ele.offsetLeft + speed + "px";         }     }, 30) }
 
  | 
 
代码举例:轮播图的实现
完整版代码如下:(注释已经比较详细)
<!doctype html> <html lang="en"> <head>     <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>     <title>无标题文档</title>     <style type="text/css">         * {             padding: 0;             margin: 0;             list-style: none;             border: 0;         }
          .all {             width: 500px;             height: 200px;             padding: 7px;             border: 1px solid #ccc;             margin: 100px auto;             position: relative;         }
          .screen {             width: 500px;             height: 200px;             overflow: hidden;             position: relative;         }
          .screen li {             width: 500px;             height: 200px;             overflow: hidden;             float: left;         }
          .screen ul {             position: absolute;             left: 0;             top: 0px;             width: 3000px;         }
          .all ol {             position: absolute;             right: 10px;             bottom: 10px;             line-height: 20px;             text-align: center;         }
          .all ol li {             float: left;             width: 20px;             height: 20px;             background: #fff;             border: 1px solid #ccc;             margin-left: 10px;             cursor: pointer;         }
          .all ol li.current {             background: yellow;         }
          #arr {             display: none;         }
          #arr span {             width: 40px;             height: 40px;             position: absolute;             left: 5px;             top: 50%;             margin-top: -20px;             background: #000;             cursor: pointer;             line-height: 40px;             text-align: center;             font-weight: bold;             font-family: '黑体';             font-size: 30px;             color: #fff;             opacity: 0.3;             border: 1px solid #fff;         }
          #arr #right {             right: 5px;             left: auto;         }     </style>
      <script>         window.onload = function () {
                                                                                                                                                
 
                           var all = document.getElementById("all");             var screen = all.firstElementChild || all.firstChild;             var imgWidth = screen.offsetWidth;             var ul = screen.firstElementChild || screen.firstChild;             var ol = screen.children[1];             var div = screen.lastElementChild || screen.lastChild;             var spanArr = div.children;
                           var ulNewLi = ul.children[0].cloneNode(true);             ul.appendChild(ulNewLi);                          for (var i = 0; i < ul.children.length - 1; i++) {                 var olNewLi = document.createElement("li");                 olNewLi.innerHTML = i + 1;                 ol.appendChild(olNewLi)             }             var olLiArr = ol.children;             olLiArr[0].className = "current";
                           for (var i = 0; i < olLiArr.length; i++) {                                  olLiArr[i].index = i;                 olLiArr[i].onmouseover = function () {                                          for (var j = 0; j < olLiArr.length; j++) {                         olLiArr[j].className = "";                     }                     this.className = "current";                     
 
                      key = square = this.index;                                          animate(ul, -this.index * imgWidth);                 }             }
                           var timer = setInterval(autoPlay, 1000);
                                        var key = 0;             var square = 0;
              function autoPlay() {                                  key++;                 if (key > olLiArr.length) {                                          ul.style.left = 0;                     key = 1;                 }                 animate(ul, -key * imgWidth);                                                   square++;                 if (square > olLiArr.length - 1) {                     square = 0;                 }                 for (var i = 0; i < olLiArr.length; i++) {                     olLiArr[i].className = "";                 }                 olLiArr[square].className = "current";             }
                           all.onmouseover = function () {                 div.style.display = "block";                 clearInterval(timer);             }             all.onmouseout = function () {                 div.style.display = "none";                 timer = setInterval(autoPlay, 1000);             }
                           spanArr[0].onclick = function () {                                  key--;                 if (key < 0) {                                          ul.style.left = -imgWidth * (olLiArr.length) + "px";                     key = olLiArr.length - 1;                 }                 animate(ul, -key * imgWidth);                                                   square--;                 if (square < 0) {                     square = olLiArr.length - 1;                 }                 for (var i = 0; i < olLiArr.length; i++) {                     olLiArr[i].className = "";                 }                 olLiArr[square].className = "current";             }             spanArr[1].onclick = function () {                                  autoPlay();             }
 
              function animate(ele, target) {                 clearInterval(ele.timer);                 var speed = target > ele.offsetLeft ? 10 : -10;                 ele.timer = setInterval(function () {                     var val = target - ele.offsetLeft;                     ele.style.left = ele.offsetLeft + speed + "px";
                      if (Math.abs(val) < Math.abs(speed)) {                         ele.style.left = target + "px";                         clearInterval(ele.timer);                     }                 }, 10)             }         }     </script> </head>
  <body> <div class="all" id='all'>     <div class="screen" id="screen">         <ul id="ul">             <li><img src="images/1.jpg" width="500" height="200"/></li>             <li><img src="images/2.jpg" width="500" height="200"/></li>             <li><img src="images/3.jpg" width="500" height="200"/></li>             <li><img src="images/4.jpg" width="500" height="200"/></li>             <li><img src="images/5.jpg" width="500" height="200"/></li>         </ul>         <ol>
          </ol>         <div id="arr">             <span id="left"><</span>             <span id="right">></span>         </div>     </div> </div> </body> </html>
 
 
   | 
 
实现效果:

温馨提示:动图太大,可以把http://img.smyhvae.com/20180202_2020.gif单独在浏览器中打开。
工程文件:
我的公众号
想学习更多技能?不妨关注我的微信公众号:千古壹号(id:qianguyihao)。
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
