Heim  >  Artikel  >  Web-Frontend  >  So implementieren Sie Offset- und einheitliche Animationen in JS

So implementieren Sie Offset- und einheitliche Animationen in JS

亚连
亚连Original
2018-06-07 14:39:291674Durchsuche

In diesem Artikel wird hauptsächlich die JavaScript-Animation vorgestellt: Offset- und einheitliche Animationen werden ausführlich erläutert (einschließlich der Implementierung von Karussellbildern) und der Implementierungscode wird interessierten Freunden als Referenz zur Verfügung gestellt.

Einführung in Offset

Wir wissen, dass die drei Hauptfamilien Folgendes umfassen: Offset/Scroll/Client. Lassen Sie uns heute über Offset und die damit verbundene einheitliche Animation sprechen.

Das chinesische Wort für Offset ist: Offset, Kompensation, Verschiebung.

Es gibt eine bequeme Möglichkeit, die Größe von Elementen in js zu ermitteln, nämlich der Offset-Familie. Die Offset-Familie umfasst:

  • offsetWidth

  • offsetHight

  • offsetLeft

  • offsetTop

  • offsetParent

werden im Folgenden separat vorgestellt.

1. offsetWidth und offsetHight

werden verwendet, um die Breite und Höhe + Innenabstand + Rand der Box selbst zu erkennen, ohne Rand. Wie folgt:

offsetWidth = width + padding + border;

offsetHeight = Height + padding + border

Diese beiden Attribute sind an alle übergeordneten Knotenelemente gebunden. Nachdem wir es erhalten haben, können wir die Breite und Höhe des Elementknotens ermitteln, indem wir diese beiden Eigenschaften aufrufen.

Zum Beispiel:

<!DOCTYPE html>
<html>
<head lang="en">
 <meta charset="UTF-8">
 <title></title>
 <style>
  p {
   width: 100px;
   height: 100px;
   padding: 10px;
   border: 10px solid #000;
   margin: 100px;
   background-color: pink;
  }
 </style>
</head>
<body>
<p class="box"></p>
<script>
 var p1 = document.getElementsByTagName("p")[0];
 console.log(p1.offsetHeight);   //打印结果:140(100+20+20)
 console.log(typeof p1.offsetHeight); //打印结果:number

</script>
</body>
</html>

2. offsetLeft und offsetTop

geben die Position links vom übergeordneten Feld zurück (mit Positionierung); Das Elternteil ist beides. Wenn keine Positionierung erfolgt, hat der Körper Vorrang.

offsetLeft: Ab der Polsterung des Vaters zählt der Rand des Vaters nicht.

Beispiel:

<!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;
   /*position: absolute;*/
   /*left: 10px;*/
   /*top: 10px;*/
  }
 </style>
</head>
<body>
<p class="box1">
 <p class="box2"></p>
</p>
<script>
 var box2 = document.getElementsByClassName("box2")[0];
 //offsetTop和offsetLeft
 console.log(box2.offsetLeft); //100
 console.log(box2.style.left); //10px
</script>
</body>
</html>

Wenn die übergeordnete Box positioniert ist, offsetLeft == style.left (nach dem Entfernen von px). Beachten Sie, dass Letzteres nur Inline-Stile erkennt. Aber der Unterschied geht darüber hinaus, wie wir später besprechen werden.

3. offsetParent

erkennt den übergeordneten Boxknoten mit Positionierung in der übergeordneten Box. Das zurückgegebene Ergebnis ist das übergeordnete Objekt des Objekts (mit Positionierung).

Wenn das übergeordnete Element des aktuellen Elements keine CSS-Positionierung hat (Position ist absolut, relativ, fest), dann ist das Rückgabeergebnis von offsetParent body.

Wenn das übergeordnete Element des aktuellen Elements eine CSS-Positionierung aufweist (Position ist absolut, relativ, fest), dann ist das Rückgabeergebnis von offsetParent das nächstgelegene übergeordnete Element.

Beispiel:

<!DOCTYPE html>
<html>
<head lang="en">
 <meta charset="UTF-8">
 <title></title>
</head>
<body>
<p class="box1">
 <p class="box2">
  <p class="box3"></p>
 </p>
</p>
<script>
 //offsetParent:复习盒子中带有定位的盒子
 //复习盒子中都没有定位,返回body
 //如果有,谁有返回最近哪个
 var box3 = document.getElementsByClassName("box3")[0];
 console.log(box3.offsetParent);
</script>
</body>
</html>

Druckergebnis:

Der Unterschied zwischen offsetLeft und style.left

(1) Der größte Unterschied ist:

offsetLeft kann die Position links vom nicht positionierten Feld zurückgeben. Wenn in der übergeordneten Box keine Positionierung erfolgt, hat der Körper Vorrang.

style.left kann nur den Inline-Stil abrufen. Wenn nicht, wird „“ zurückgegeben (d. h. leer zurückgegeben). (2) offsetTop gibt eine Zahl zurück, während style.top zurückgibt ist ein String und hat auch die Einheit: px.

Zum Beispiel:

p.offsetLeft = 100;
p.style.left = "100px";

(3) offsetLeft und offsetTop sind schreibgeschützt, während style.left und style.top gelesen und geschrieben werden können (schreibgeschützt dient zum Abrufen des Werts). und beschreibbar ist, den Wert zuzuweisen)

(4) Wenn der Top-Stil für das HTML-Element nicht angegeben ist, gibt style.top eine leere Zeichenfolge zurück.

Zusammenfassung: Unser allgemeiner Ansatz ist: Verwenden Sie offsetLeft und offsetTop, um den Wert zu erhalten, und verwenden Sie style.left und style.top, um den Wert zuzuweisen (praktischer). Die Gründe sind wie folgt:

style.left: Es können nur Inline-Stile abgerufen werden, und der erhaltene Wert ist möglicherweise leer, was zu NaN führt.

offsetLeft: Es ist besonders praktisch, den Wert zu erhalten, und es handelt sich um eine vorgefertigte Zahl zur einfachen Berechnung. Es ist schreibgeschützt und es kann kein Wert zugewiesen werden.

Animationsarten

    Blitz (grundsätzlich nicht verwendet)
  • Konstante Geschwindigkeit (der Schwerpunkt dieses Artikels)
  • Easing (Follow-up-Fokus)
  • Ein einfaches Beispiel ist wie folgt: (Alle 500 ms das Feld um 100 Pixel nach rechts verschieben)
<!DOCTYPE html>
<html>
<head lang="en">
 <meta charset="UTF-8">
 <title></title>
 <style>
  p {
   width: 100px;
   height: 100px;
   background-color: pink;
   position: absolute;
  }
 </style>
</head>
<body>
<button>动画</button>
<p class="box"></p>

<script>
 var btn = document.getElementsByTagName("button")[0];
 var p = document.getElementsByTagName("p")[0];

 //1、闪动
 // btn.onclick = function () {
 //  p.style.left = "500px";
 // }

 //2、匀速运动
 btn.onclick = function () {
  //定时器,每隔一定的时间向右走一些
  setInterval(function () {
   console.log(parseInt(p.style.left));
   //动画原理: 盒子未来的位置 = 盒子现在的位置 + 步长;
   //用style.left赋值,用offsetLeft获取值。
   p.style.left = p.offsetLeft + 100 + "px";
   //p.style.left = parseInt(p.style.left)+10+"px"; //NaN不能用

  }, 500);
 }
</script>
</body>
</html>

Der Effekt ist wie folgt:

Einheitliche Animationskapselung: Bewegen Sie das Feld alle 30 ms um 10 Pixel [Wichtig]

Der Code lautet wie folgt:

<!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>
<p class="box1">
 <button>运动到 left = 200px</button>
 <button>运动到 left = 400px</button>
 <p class="box2"></p>
 <p class="box3"></p>
</p>

<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);
 }

 //【重要】方法的封装:每间隔30ms,将盒子向右移动10px
 function animate(ele, target) {
  //要用定时器,先清除定时器
  //一个盒子只能有一个定时器,这样的话,不会和其他盒子出现定时器冲突
  //我们可以把定时器本身,当成为盒子的一个属性
  clearInterval(ele.timer);
  //我们要求盒子既能向前又能向后,那么我们的步长就得有正有负
  //目标值如果大于当前值取正,目标值如果小于当前值取负
  var speed = target > ele.offsetLeft ? 10 : -10; //speed指的是步长
  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>

Der erzielte Effekt:

Die Methodenkapselung im obigen Code kann als Vorlagenschritt verwendet werden. Denken Sie also daran. Tatsächlich ist diese Kapselungsmethode strenger und leichter zu verstehen, wenn sie wie folgt geschrieben wird: (verbesserte if-Anweisung)

 //【重要】方法的封装:每间隔30ms,将盒子向右移动10px
 function animate(ele, target) {
  //要用定时器,先清除定时器
  //一个盒子只能有一个定时器,这样的话,不会和其他盒子出现定时器冲突
  //我们可以把定时器本身,当成为盒子的一个属性
  clearInterval(ele.timer);
  //我们要求盒子既能向前又能向后,那么我们的步长就得有正有负
  //目标值如果大于当前值取正,目标值如果小于当前值取负
  var speed = target > ele.offsetLeft ? 10 : -10; //speed指的是步长
  ele.timer = setInterval(function () {
   //在执行之前就获取当前值和目标值之差
   var val = target - ele.offsetLeft;

   //移动的过程中,如果目标值和当前值之差如果小于步长,那么就不能在前进了
   //因为步长有正有负,所有转换成绝对值来比较
   if (Math.abs(val) < Math.abs(speed)) { //如果val小于步长,则直接到达目的地;否则,每次移动一个步长
    ele.style.left = target + "px";
    clearInterval(ele.timer);
   } else {
    ele.style.left = ele.offsetLeft + speed + "px";
   }
  }, 30)
 }

Codebeispiel: Implementierung eines Karusselldiagramms

Vollversion Der Code lautet wie folgt folgt: (die Kommentare sind detaillierter)

<!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: &#39;黑体&#39;;
   font-size: 30px;
   color: #fff;
   opacity: 0.3;
   border: 1px solid #fff;
  }

  #arr #right {
   right: 5px;
   left: auto;
  }
 </style>

 <script>
  window.onload = function () {

   //需求:无缝滚动。
   //思路:赋值第一张图片放到ul的最后,然后当图片切换到第五张的时候
   //  直接切换第六章,再次从第一张切换到第二张的时候先瞬间切换到
   //  第一张图片,然后滑动到第二张
   //步骤:
   //1.获取事件源及相关元素。(老三步)
   //2.复制第一张图片所在的li,添加到ul的最后面。
   //3.给ol中添加li,ul中的个数-1个,并点亮第一个按钮。
   //4.鼠标放到ol的li上切换图片
   //5.添加定时器
   //6.左右切换图片(鼠标放上去隐藏,移开显示)


   //1.获取事件源及相关元素。(老三步)
   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 p = screen.lastElementChild || screen.lastChild;
   var spanArr = p.children;

   //2.复制第一张图片所在的li,添加到ul的最后面。
   var ulNewLi = ul.children[0].cloneNode(true);
   ul.appendChild(ulNewLi);
   //3.给ol中添加li,ul中的个数-1个,并点亮第一个按钮。
   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";

   //4.鼠标放到ol的li上切换图片
   for (var i = 0; i < olLiArr.length; i++) {
    //自定义属性,把索引值绑定到元素的index属性上
    olLiArr[i].index = i;
    olLiArr[i].onmouseover = function () {
     //排他思想
     for (var j = 0; j < olLiArr.length; j++) {
      olLiArr[j].className = "";
     }
     this.className = "current";
     //鼠标放到小的方块上的时候索引值和key以及square同步
//     key = this.index;
//     square = this.index;
     key = square = this.index;
     //移动盒子
     animate(ul, -this.index * imgWidth);
    }
   }

   //5.添加定时器
   var timer = setInterval(autoPlay, 1000);

   //固定向右切换图片
   //两个定时器(一个记录图片,一个记录小方块)
   var key = 0;
   var square = 0;

   function autoPlay() {
    //通过控制key的自增来模拟图片的索引值,然后移动ul
    key++;
    if (key > olLiArr.length) {
     //图片已经滑动到最后一张,接下来,跳转到第一张,然后在滑动到第二张
     ul.style.left = 0;
     key = 1;
    }
    animate(ul, -key * imgWidth);
    //通过控制square的自增来模拟小方块的索引值,然后点亮盒子
    //排他思想做小方块
    square++;
    if (square > olLiArr.length - 1) {//索引值不能大于等于5,如果等于5,立刻变为0;
     square = 0;
    }
    for (var i = 0; i < olLiArr.length; i++) {
     olLiArr[i].className = "";
    }
    olLiArr[square].className = "current";
   }

   //鼠标放上去清除定时器,移开后在开启定时器
   all.onmouseover = function () {
    p.style.display = "block";
    clearInterval(timer);
   }
   all.onmouseout = function () {
    p.style.display = "none";
    timer = setInterval(autoPlay, 1000);
   }

   //6.左右切换图片(鼠标放上去显示,移开隐藏)
   spanArr[0].onclick = function () {
    //通过控制key的自增来模拟图片的索引值,然后移动ul
    key--;
    if (key < 0) {
     //先移动到最后一张,然后key的值取之前一张的索引值,然后在向前移动
     ul.style.left = -imgWidth * (olLiArr.length) + "px";
     key = olLiArr.length - 1;
    }
    animate(ul, -key * imgWidth);
    //通过控制square的自增来模拟小方块的索引值,然后点亮盒子
    //排他思想做小方块
    square--;
    if (square < 0) {//索引值不能大于等于5,如果等于5,立刻变为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>
<p class="all" id=&#39;all&#39;>
 <p class="screen">
  <ul>
   <li><img src="images/1.jpg"/></li>
   <li><img src="images/2.jpg"/></li>
   <li><img src="images/3.jpg"/></li>
   <li><img src="images/4.jpg"/></li>
   <li><img src="images/5.jpg"/></li>
  </ul>
  <ol>

  </ol>
  <p>
   <span><</span>
   <span>></span>
  </p>
 </p>
</p>
</body>
</html>

Erfolgseffekt:

Das Obige ist das, was ich für alle zusammengestellt habe. Ich hoffe, dass es hilfreich sein wird alle in der Zukunft.

Verwandte Artikel:

Verwendung von Node.js zur Implementierung von Komprimierungs- und Dekomprimierungsfunktionen

Fragen zu Vue-gepackten Kartendateien

So implementieren Sie die Front-End-Sternebewertungsfunktionskomponente mit vue2.0

Das obige ist der detaillierte Inhalt vonSo implementieren Sie Offset- und einheitliche Animationen in JS. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn