四、定时器实现动画
4.1、js实现动画(不推荐)
需求:使用js来实现盒子的移动。从40px -> 600px,2s。
弊端:若是仅仅通过使用js来实现动画,这是十分麻烦的,例如你想要2s实现的一个动画,你需要去计算每秒其移动多少距离,每秒移动多少次,这需要进行大量计算,并且若是你还想设置返回动画,那就还需要进行更多的逻辑判断。
现在有许多的一些三方库给我们封装好,如jquery等。更好的方式还是js+css动画来进行配合使用!
<style> * { margin: 0; padding: 0; } div.box { width: 100px; height: 100px; border: 1px solid #000; background-color: orange; margin: 40px; } </style> <body> <div class="box" id="box"></div> <script> var m_box = document.getElementById("box"); var left = 30; m_box.onclick = function () { var myInterval = setInterval(function () { left += 2; //设置盒子停止时机 if (left >= 600) { //指定到600px停止,清除定时器 clearInterval(myInterval); } m_box.style.marginLeft = left + "px"; }, 7); //一秒中执行50次,预计设想2秒移动 => 移动距离560px。 //1s就是280px,每次移动2px,那就是1s移动140次;1分钟1000毫秒,那就是设置7ms一次。 }; </script> </body>
4.2、js+css配合实现动画
实现盒子左右移动(过渡+基本判断)
需求:我们点击一个按钮,让盒子移动到右边,再点击一下盒子移动到左边。
分析:
使用css动画来实现过渡效果:m_box.style.transition = "all 2s linear 0s";。
对于点击从左到右、从右到左通过js来进行控制。(通过判断postion属性来进行操作)
源码:
<style> * { margin: 0; padding: 0; } div.box { position: absolute; top: 30px; left: 40px; width: 100px; height: 100px; border: 1px solid #000; background-color: orange; } </style> <body> <button>点我移动</button> <div class="box" id="box"></div> <script> var m_button = document.getElementsByTagName("button")[0]; var m_box = document.getElementById("box"); var position = 0;//0:左边,1:右边 m_button.onclick = function () { //1、使用css动画来实现过渡效果 m_box.style.transition = "all 2s linear 0s"; //2、js来编程进行左右的移动效果 if (position == 0) { m_box.style.left = "1000px"; position = 1; } else if (position == 1) { m_box.style.left = "40px"; position = 0; } }; </script> </body>
案例出现问题(通过函数节流解决)
问题抛出
问题说明:虽说上面实现了通过按钮点击进行盒子的左右移动效果,但是若是我们在该盒子移动过程中多次去点击按钮,就会出现下面情况。
按理说是要先移动到右边,再进行移动到左边,可是中途进行点击就会一下子立马又向左移,我们如何来实现向左或向右完整执行2s再进行相反的移动呢?
解决方案:使用函数节流
函数节流:该名词是这样定义的,当一个函数执行一次后,只有大于设定的执行周期后才允许执行第二次。
固定模板:
var lock = true;//默认为true,表示开锁,允许进行下一步操作了 function 指定需要函数节流函数(){ //如果当前为false(表示已经上锁),不往下执行 if(!lock) return; //函数结束 //关锁 lock = false; xxx; //一些业务操作 //使用延时器来等待2秒后开锁(时间根据指定情况来定),到时间了就开锁 setTimeout(function(){ lock = true; },2000); }
优化上面的左右移动案例:只有动画执行完之后点击才有效(通过使用上方模板)
<style> * { margin: 0; padding: 0; } div.box { position: absolute; top: 30px; left: 40px; width: 100px; height: 100px; border: 1px solid #000; background-color: orange; } </style> <body> <button>点我移动</button> <div class="box" id="box"></div> <script> var m_button = document.getElementsByTagName("button")[0]; var m_box = document.getElementById("box"); var position = 0;//0:左边,1:右边 //1、锁:true为开锁,false为上锁 var lock = true; m_button.onclick = function () { //2、若是lock为false,表示上锁,直接退出函数 if (!lock) return; //3、若是lock为true表示现在开着锁,继续向下执行,这里设置为false,表示此时在执行业务所以上锁 lock = false; m_box.style.transition = "all 2s linear 0s"; if (position == 0) { m_box.style.left = "1000px"; position = 1; } else if (position == 1) { m_box.style.left = "40px"; position = 0; } //4、使用延时器,由于动画是2s,所以这里设置2s后开锁! setTimeout(function () { lock = true; }, 2000); }; </script> </body>
实际案例
1、无缝连续滚动特效
效果与分析
需求:制作一个展示栏,展示栏中有多张图片(这里使用小盒子来替代),会不断进行连续滚动。当鼠标触碰进盒子就会暂停,离开盒子就会继续连续滚动。
思路分析:
首先是结构分析:外层使用了一个盒子,内部是ul的列表(使用了左浮动)。其中其中的div外盒子设置宽度为300px,但是为了让li元素都在一行上,就需要设置ul的宽度为1300px。
<div class="box"> <ul> <li>1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> <li>6</li> <li>7</li> </ul> </div>
我们来剖析一下原理:
我们把div的overflow: hidden取消,你就可以看到真面目了,里面有两倍的盒子(方便每一个盒子都能被看到),通过使用定时器来实现整个盒子的移动,并没有使用css的动画属性,当定时器中盒子到达指定left位置时,就重新设置left=0,重新进行循环进行。
额外说明的是:本次案例添加了两个事件,一个是鼠标移入,另一个是鼠标移出,分别是对定时器的设置与清除。
源码
<style> * { margin: 0; padding: 0; } div.box { position: relative; width: 300px; height: 62px; overflow: hidden; border: 1px solid #000; margin: 20px auto; } div.box ul { position: absolute; /*0一直到-330px表示一趟结束 */ left: 0; list-style: none; /* 设置内部的ul宽度大一些,来支撑原本内部元素的长度 */ width: 1300px; } div.box li { float: left; height: 60px; width: 80px; border: 1px solid #000; text-align: center; line-height: 60px; margin-right: 10px; background-color: orange; } div.box li:nth-child(1) { background-color: red; } div.box li:nth-child(2) { background-color: blue; } div.box li:nth-child(3) { background-color: green; } div.box li:nth-child(4) { background-color: gold; } div.box li:nth-child(5) { background-color: goldenrod; } div.box li:nth-child(6) { background-color: orange; } div.box li:nth-child(7) { background-color: gray; } </style> <body> <div class="box"> <ul> <li>1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> <li>6</li> <li>7</li> </ul> </div> <script> var m_ul = document.getElementsByTagName("ul")[0]; //复制一份待移动的多个小盒子(方便每个盒子都能够预览到) m_ul.innerHTML += m_ul.innerHTML; //全局变量:ul左边距离 var l = 0; //全局变量:定时器的ID号 var inervalID //创建定时器 function setShowInterval() { clearInterval(inervalID);//一定要记得清除事件 //设置定时器 inervalID = setInterval(function () { l -= 4; if (l <= -850) { l = 0; } m_ul.style.left = l + "px"; }, 20); } //初始化时要创建定时器 setShowInterval(); //鼠标移入与移除事件 //为ul设置鼠标移入事件:定时器停止 m_ul.onmouseenter = function () { clearInterval(inervalID); } //为ul设置鼠标移出事件:设置定时器 m_ul.onmouseleave = function () { setShowInterval(); } </script> </body>
2、跑马灯轮播图(左右翻图)
实际原理与案例1的无缝连续滚动相同,只不过这里将第一个图片多复制了一份到后面。
使用到的知识点如:
克隆节点+点击事件,css+js配合实现动画效果。
对于前后切换图片(快速无痕切换),需要将transication属性在none、all .5s ease 0s两者间进行切换。
函数节点(控制动画效果能够顺利完成)。
效果展示:点击左右按钮实现图片翻页
源码:
<style> * { margin: 0; padding: 0; font-size: large; font-weight: bolder; } div.box { position: relative; width: 350px; height: 230px; margin: 20px auto; border: 1px solid #000; overflow: hidden; } div.box ul { list-style: none; /* 350*5=1750 */ width: 1750px; position: absolute; left: 0; } div.box ul li { float: left; } img { width: 350px; height: 230px; } a { text-decoration: none; position: absolute; width: 30px; height: 30px; border-radius: 15px; background-color: rgba(255, 255, 255, .5); text-align: center; line-height: 30px; } a:nth-of-type(1) { top: 50%; left: 0; margin-top: -15px; } a:nth-of-type(2) { top: 50%; right: 0; margin-top: -15px; } </style> <body> <div class="box"> <ul> <li><img src="./images/img_01.jpg" alt=""></li> <li><img src="./images/img_02.jpg" alt=""></li> <li><img src="./images/img_03.jpg" alt=""></li> <li><img src="./images/img_04.jpg" alt=""></li> </ul> <a href="javascript:;"><</a> <a href="javascript:;">></a> </div> <script> //宽为230px //两个按钮节点 var firstA = document.getElementsByTagName("a")[0]; var secondA = document.getElementsByTagName("a")[1]; //ul元素 var myul = document.getElementsByTagName("ul")[0] var currentImgPos = 0;//表示第几张图片 //为ul结尾添加第一张图 myul.appendChild(document.getElementsByTagName("li")[0].cloneNode(true)); //用于函数节点操作 var lock = true; //给左按钮绑定单击事件 firstA.onclick = function () { if (!lock) return; lock = false; myul.style.transition = "all .5s ease 0s"; currentImgPos++; //若是已经到达了第五张图,通过使用延时器来快速回到原本位置 if (currentImgPos == 4) { //使用延时器恢复原来的过渡效果 setTimeout(function () { myul.style.transition = "none"; currentImgPos = 0; myul.style.left = 0 + "px"; }, 500); } myul.style.left = -currentImgPos * 350 + "px"; //设置0.5s(与切换一张图片相同时长释放锁) setTimeout(function () { lock = true; }, 500) }; // 点击右边按钮 secondA.onclick = function () { if (!lock) return; lock = false; //一旦图片是第一张往前移 if (currentImgPos == 0) { // 快速移动到最后一张图片上 myul.style.transition = "none"; myul.style.left = -4 * 350 + "px"; //这个延时器就设置为0s,在其后进行向前移动效果(含过渡) setTimeout(function () { myul.style.transition = "all .5s ease 0s"; currentImgPos = 3; myul.style.left = -currentImgPos * 350 + "px"; }, 0); } else { //正常向前移动 currentImgPos--; myul.style.left = -currentImgPos * 350 + "px"; } //设置0.5s(与切换一张图片相同时长释放锁) setTimeout(function () { lock = true; }, 500) } </script> </body>
3、呼吸轮播图
分析:同样也是轮播图,通过点击左右按钮的方式来进行淡入淡出的。想要制作出这类效果,需要将多张图片全部堆叠在一起,初始三张图片设置透明度为0,另外一张透明度为1。之后对透明度参数设置过渡效果实现!
源码:
<style> * { margin: 0; padding: 0; font-size: large; font-weight: bolder; } div.box { position: relative; width: 350px; height: 230px; margin: 20px auto; border: 1px solid #000; /* overflow: hidden; */ } div.box ul { list-style: none; /* 350*5=1750 */ width: 1750px; position: absolute; left: 0; } div.box ul li { position: absolute; left: 0; top: 0; /* 透明度为0 */ opacity: 0; transition: all 1s linear 0s; } div.box ul li:nth-child(1) { /* 透明度为1 */ opacity: 1; } img { width: 350px; height: 230px; } a { text-decoration: none; position: absolute; width: 30px; height: 30px; border-radius: 15px; background-color: rgba(255, 255, 255, .5); text-align: center; line-height: 30px; } a:nth-of-type(1) { top: 50%; left: 0; margin-top: -15px; } a:nth-of-type(2) { top: 50%; right: 0; margin-top: -15px; } </style> <body> <div class="box"> <ul> <li><img src="./images/img_01.jpg" alt=""></li> <li><img src="./images/img_02.jpg" alt=""></li> <li><img src="./images/img_03.jpg" alt=""></li> <li><img src="./images/img_04.jpg" alt=""></li> </ul> <a href="javascript:;"><</a> <a href="javascript:;">></a> </div> <script> //宽为230px //两个按钮节点 var firstA = document.getElementsByTagName("a")[0]; var secondA = document.getElementsByTagName("a")[1]; //li元素 var lists = document.getElementsByTagName("li"); var pos = 0;//表示当前照片的位置 //用于函数节点操作 var lock = true; //给左按钮绑定单击事件 firstA.onclick = function () { if (!lock) return; lock = false; //老图淡出 lists[pos].style.opacity = 0; pos++; if (pos > 3) { pos = 0; } //新图淡入 lists[pos].style.opacity = 1; setTimeout(function () { lock = true; }, 1000); }; //给右按钮绑定单击事件 secondA.onclick = function () { if (!lock) return; lock = false; //老图淡出 lists[pos].style.opacity = 0; pos--; if (pos < 0) { pos = 3; } //新图淡入 lists[pos].style.opacity = 1; setTimeout(function () { lock = true; }, 1000); }; </script> </body>