Home > Article > Web Front-end > How to implement offset and uniform animation in JS
This article mainly introduces JavaScript animation: detailed explanation of offset and uniform animation (including the implementation of carousel images), and shares the implementation code for reference by interested friends.
We know that the three major families include: offset/scroll/client. Today, let’s talk about offset and its related uniform animation.
offset in Chinese is: offset, compensation, displacement.
There is a convenient way to get the size of elements in js, which is the offset family. The offset family includes:
offsetWidth
offsetHight
offsetLeft
offsetTop
offsetParent
are introduced below.
1, offsetWidth and offsetHight
are used to detect the width and height padding border of the box itself, excluding margin. As follows:
offsetWidth = width padding border;
offsetHeight = Height padding border;
These two properties are bound to all node elements. After getting it, we can get the width and height of the element node by calling these two properties.
For example:
<!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 and offsetTop
Return the position to the left of the parent box (with positioning); if the parent is If there is no positioning, the body will prevail.
offsetLeft: Starting from the father’s padding, the father’s border does not count.
Example:
<!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>
When the parent box is positioned, offsetLeft == style.left (after removing px). Note that the latter only recognizes inline styles. But the difference goes beyond that, as we’ll talk about later.
3. offsetParent
Detects the parent box node with positioning in the parent box. The returned result is the object's parent (with positioning).
If the parent element of the current element has no CSS positioning (position is absolute, relative, fixed), then the return result of offsetParent is body.
If the parent element of the current element has CSS positioning (position is absolute, relative, fixed), then the return result of offsetParent is the nearest parent element.
Example:
<!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>
Print result:
##The difference between offsetLeft and style.left
(1) The biggest difference is: offsetLeft can return the position to the left of the unpositioned box. If there is no positioning in the parent box, the body will prevail. style.left can only get the inline style. If not, it will return "" (meaning, return empty); (2) offsetTop returns a number, while style.top returns is a string, and also has the unit: px. For example:p.offsetLeft = 100; p.style.left = "100px";(3) offsetLeft and offsetTop are read-only, while style.left and style.top can be read and written (read-only is to get the value, and writable is to assign the value)
(4) If the top style is not specified for the HTML element, style.top returns an empty string. Summary: Our general approach is: use offsetLeft and offsetTop to obtain the value, and use style.left and style.top to assign the value (more convenient). The reasons are as follows: style.left: Only inline styles can be obtained, and the obtained value may be empty, which is prone to NaN. offsetLeft: It is particularly convenient to obtain the value, and it is a ready-made number, which is convenient for calculation. It is read-only and cannot be assigned a value. Types of animation
<!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>The effect is as follows:
Uniform speed animation encapsulation: every 30ms interval, move the box 10px [Important]
The code is as follows:<!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>The effect achieved:
The method encapsulation in the above code can be used as a template step, so remember it. In fact, this encapsulation method, written as follows, will be more rigorous and easier to understand: (improved if statement)
//【重要】方法的封装:每间隔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) }Code example: implementation of carousel chartFull version The code is as follows: (the comments are more detailed)
<!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 () { //需求:无缝滚动。 //思路:赋值第一张图片放到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='all'> <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>Achievement effect:
The above is what I compiled for everyone. I hope it will be helpful to everyone in the future.
Related articles:Using Node.js to implement compression and decompression functions
Questions about Vue packaging map files
How to implement the front-end star rating function component using vue2.0
The above is the detailed content of How to implement offset and uniform animation in JS. For more information, please follow other related articles on the PHP Chinese website!