一、定时器
BOM 中有两中方式设置定时器。
1、方式一
特点:定时器可以重复使用。
// 参数有两个:// 第一个参数:定时器定时结束处理函数// 第二个参数:定时事件,单位毫秒。// 返回值:定时器id值var timeId = window.setInterval(function() { // ...}, 1000); // 定时1s// 清除定时器// 参数只有一个:定时器的 id 值。window.clearInterval(timeId);
1.1、案例:图片摇起来
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title> <style> div { position: absolute; } </style></head><body><input type="button" value="摇起来" id="btn1"><input type="button" value="停止" id="btn2"><div id="dv"> <img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="images/Daotin.png" alt=""></div><script class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="common.js"></script><script> var timeId = 0; my$("btn1").onclick = function () { timeId = setInterval(function () { //让图片动起来可以使div动起来 var x = parseInt(Math.random() * 100) + 1; // 1-100随机数 var y = parseInt(Math.random() * 100) + 1; my$("dv").style.left = x + "px"; my$("dv").style.top = y + "px"; }, 100); }; my$("btn2").onclick = function () { clearInterval(timeId); };</script></body></html>
点击”摇起来“按钮,图片每隔 100ms 动一次,点击停止按钮,图片停止移动。
遗留问题:
多次点击“摇起来”按钮的时候,图片动的越来越快,而且点击“停止”按钮没法停下来。
原因分析:
多次点击“摇起来”按钮的时候,timeId 的值会有多个,而停止的时候,只会清理最后一个值,其他的值对应的定时器没有清理。
解决方法:
在每次点击按钮的时候,先进行一次定时器的清理动作。clearInterval(timeId);
2、方式二
特点:定时器是一次性的。
setTimeout(); // 参数与返回值同 setInterval();
这个定时器只执行一次。虽然只执行一次,但是还是要清零,不然就一直占内存。
clearTimeOut(); // 参数为 setTimeout() 定时器的 id。
2.1、案例:协议禁用倒计时
<body><input type="button" value="请认真阅读协议(5)" id="btn" disabled><script class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="common.js"></script><script> var time = 5; var timeId = setInterval(function () { time--; if (time >= 0) { my$("btn").value = "请认真阅读协议(" + time + ")"; } else { clearInterval(timeId); my$("btn").value = "同意"; my$("btn").disabled = false; } }, 1000);</script></body>
倒计时后才可以点击同意按钮。
2.2、案例:移动元素
目标:有两个按钮,点击第一个按钮,div 缓慢移动到 400px 位置,点击第二个按钮缓慢移动到 800px 位置,再点击第一个按钮缓慢移动到 400px 位置......
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title> <style> * { margin: 0; padding: 0; } input { margin-top: 10px; } div { position: absolute; width: 200px; height: 100px; background-color: yellowgreen; margin-top: 10px; /*left: 20px;*/ } </style></head><body><input type="button" value="移动400px" id="btn1"><input type="button" value="移动800px" id="btn2"><div id="dv"></div><script class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="common.js"></script><script> // 移动400px my$("btn1").onclick = function () { animation(my$("dv"), 400); }; // 移动800px my$("btn2").onclick = function () { animation(my$("dv"), 800); }; // 封装动画移动函数 function animation(element, target) { // 判断当前的位置 var current = element.offsetLeft; // 不能使用 element.style.left var onestep = 7; var timeId = setInterval(function () { current += current < target ? onestep : -onestep; if (Math.abs(current - target) >= onestep) { element.style.left = current + "px"; } else { clearInterval(timeId); element.style.left = target + "px"; } }, 20); }</script></body></html>
1、既然要缓慢移动,就需要定时器。
2、当前位置的获取不能使用 element.style.left; 而需要使用 element.offsetLeft; 因为所有写在标签中的 style 属性值都拿不到,只有内联的 style 属性值可以使用 element.style.left 拿到。而 element.offsetLeft 则两种方式都可以拿到。
3、需要每次移动的步数 onestep,而且有回退的需要,所以 onestep 可能是负数。
4、每次移动后判断现在的位置到目标位置的距离,如果大于 onestep,那么就移动 当前 current 加减 onestep 的位置,否则就移动到目标位置,这样做的目的是避免 onestep 的不确定,导致最后的终点与目标还差少许的距离。
5、使用当前与目标距离的绝对值来决定是前进还是后退。
6、到达目标位置后,关闭定时器。
7、将动画过程封装成一个函数,参数为移动的目标和移动的距离。
8、注意:div 需要脱离文档流。
2.3、案例:轮播图
2.3.1、简单的轮播图
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title> <style> * { margin: 0; padding: 0; } #box { width: 400px; height: 250px; margin: 200px 0 0 400px; position: relative; border: 2px solid #31608a; overflow: hidden; } ul { width: 1300px; position: absolute; } li { list-style-type: none; float: left; } img { width: 400px; height: 250px; } li a { display: inline-block; } .sp { position: absolute; left: 50%; margin-left: -45px; bottom: 10px; } span { float: left; width: 20px; height: 20px; background-color: #fff; border-radius: 10px; text-align: center; font: 400 16px/20px Consolas; margin: 0 5px 0 5px; cursor: pointer; } .current { background-color: red; color: #fff; } </style></head><body><div id="box"> <ul> <li><a href="#"><img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="images/img1.jpg" alt=""></a></li> <li><a href="#"><img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="images/img2.jpg" alt=""></a></li> <li><a href="#"><img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="images/img3.jpg" alt=""></a></li> </ul> <div class="sp"> <span class="current">1</span> <span>2</span> <span>3</span> </div></div><script class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="common.js"></script><script> // 获取box元素 var boxObj = my$("box"); // 获取ul元素,因为移动的就是整个ul var ulObj = boxObj.children[0]; // 移动宽度 var moveWidth = document.getElementsByTagName("img")[0].offsetWidth; // 获取所有span标签 var spanObjs = boxObj.children[1].getElementsByTagName("span"); // console.log(spanObjs); for (var i = 0; i < spanObjs.length; i++) { // 获取每个span的编号,设置自定义属性 spanObjs[i].setAttribute("index", "" + i); spanObjs[i].onmouseover = function () { for (var j = 0; j < spanObjs.length; j++) { // 清空span背景 spanObjs[j].removeAttribute("class"); } // 设置当前span标签 this.className = "current"; // 每个编号*移动的宽度就是移动到的目标位置 var index = this.getAttribute("index"); animation(ulObj, -index*moveWidth); }; } // 封装动画移动函数 function animation(element, target) { // 判断当前的位置 var current = element.offsetLeft; var onestep = 7; var timeId = setInterval(function () { current += current < target ? onestep : -onestep; if (Math.abs(current - target) >= onestep) { element.style.left = current + "px"; } else { clearInterval(timeId); element.style.left = target + "px"; } }, 10); }</script></body></html>
1、移动的时候移动的是 ul,而不是单独的 li 或者 img。
2、span 小标签在鼠标进入的时候,背景变成红色。(排他事件:需要两步,第一清理所有,第二当前元素设置属性)
3、为每个 span 绑定事件时,程序开始,for 循环就运行完了,得不到每个span 标签的编号,所以要自定义属性保存每个 span 标签的编号。
4、直接调用封装好的动画移动函数来移动 ul 标签。
2.3.2、左右焦点轮播图
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title> <style> * { margin: 0; padding: 0; } #box { width: 400px; height: 250px; margin: 200px 0 0 400px; position: relative; border: 2px solid #31608a; overflow: hidden; } ul { width: 1300px; position: absolute; } li { list-style-type: none; float: left; } img { width: 400px; height: 250px; } .sp { width: 400px; height: 50px; position: absolute; top: 100px; display: none; } #left { width: 50px; height: 50px; float: left; cursor:pointer; text-align:center; font: 400 28px/50px Consolas; background-color: #fff; opacity: 0.4; /* 透明度 */ } #right { float: right; width: 50px; height: 50px; cursor:pointer; text-align:center; font: 400 28px/50px Consolas; background-color: #fff; opacity: 0.4; } </style></head><body><div id="box"> <ul> <li><a href="#"><img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="images/img1.jpg" alt=""></a></li> <li><a href="#"><img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="images/img2.jpg" alt=""></a></li> <li><a href="#"><img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="images/img3.jpg" alt=""></a></li> </ul> <div class="sp"> <span id="left"><</span> <span id="right">></span> </div></div><script class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="common.js"></script><script> // 获取box元素 var boxObj = my$("box"); // 获取ul元素,因为移动的就是整个ul var ulObj = boxObj.children[0]; // 移动宽度 var moveWidth = document.getElementsByTagName("img")[0].offsetWidth; // 获取sp标签 var spObj =boxObj.children[1]; // 获取span左标签 var leftObj = my$("left"); // 获取span右标签 var rightObj = my$("right"); var index = 0; boxObj.onmouseover = function () { spObj.style.display = "block"; }; boxObj.onmouseout = function () { spObj.style.display = "none"; }; // 左移 leftObj.onclick = function () { if(index) { index--; animation(ulObj, -index*moveWidth); } }; // 右移 rightObj.onclick = function () { if(index<ulObj.children.length-1) { index++; animation(ulObj, -index*moveWidth); } }; // 封装动画移动函数 function animation(element, target) { // 判断当前的位置 var current = element.offsetLeft; var onestep = 17; var timeId = setInterval(function () { current += current < target ? onestep : -onestep; if (Math.abs(current - target) >= onestep) { element.style.left = current + "px"; } else { clearInterval(timeId); element.style.left = target + "px"; } }, 10); }</script></body></html>
2.3.3、完整轮播图
需求:鼠标进入数字按钮自动切换;鼠标点击左右切换按钮切换,并且数字按钮跟着切换;自动轮播。
代码:
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="base.css"> <style> * { margin: 0; padding: 0; } #box { width: 400px; height: 250px; margin: 100px 0 0 400px; position: relative; border: 2px solid #31608a; overflow: hidden; } ul { width: 1300px; position: absolute; } li { list-style-type: none; float: left; } img { width: 400px; height: 250px; } .sp { position: absolute; left: 50%; margin-left: -45px; bottom: 10px; } span { float: left; width: 20px; height: 20px; background-color: #fff; border-radius: 10px; text-align: center; font: 400 16px/20px Consolas; margin: 0 5px 0 5px; cursor: pointer; } .spdiv { width: 400px; height: 50px; position: absolute; top: 100px; display: none; } #left { width: 50px; height: 50px; float: left; cursor: pointer; text-align: center; font: 400 28px/50px Consolas; color: #fff; background-color: rgba(255, 255, 255, 0.3); } #right { float: right; width: 50px; height: 50px; cursor: pointer; text-align: center; font: 400 28px/50px Consolas; color: #fff; background-color: rgba(255, 255, 255, 0.3); } .current { background-color: red; color: #fff; } </style></head><body><div id="box"> <ul> <li><a href="#"><img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="images/img1.jpg" alt=""></a></li> <li><a href="#"><img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="images/img2.jpg" alt=""></a></li> <li><a href="#"><img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="images/img3.jpg" alt=""></a></li> </ul> <div class="sp"> <span class="current">1</span> <span>2</span> <span>3</span> </div> <div class="spdiv"> <s id="left"><</s> <s id="right">></s> </div></div><script class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="common.js"></script><script> // 获取box元素 var boxObj = my$("box"); // 获取ul元素,因为移动的就是整个ul var ulObj = boxObj.children[0]; // 移动宽度 var moveWidth = document.getElementsByTagName("img")[0].offsetWidth; // 获取ul中所有的li var liObjs = ulObj.children; ulObj.appendChild(liObjs[0].cloneNode(true)); // 克隆第一个li,加入到ul中的最后 ulObj.style.width = ulObj.offsetWidth + moveWidth + "px"; // 重新设置ul的宽度 // 获取所有span标签 var spanObjs = boxObj.children[1].getElementsByTagName("span"); // console.log(spanObjs); // 获取spdiv标签 var spdivObj = boxObj.children[2]; // 获取span左标签 var leftObj = my$("left"); // 获取span右标签 var rightObj = my$("right"); var pos = 0; var myTimeId = setInterval(moveRight, 1000); // 自动播放 + 鼠标进入事件 boxObj.onmouseover = function () { spdivObj.style.display = "block"; clearInterval(myTimeId); }; boxObj.onmouseout = function () { spdivObj.style.display = "none"; myTimeId = setInterval(moveRight, 1000); }; // 左移 leftObj.onclick = function () { if (pos === 0) { pos = spanObjs.length; ulObj.style.left = -spanObjs.length * moveWidth + "px"; } pos--; animation(ulObj, -pos * moveWidth); for (var i = 0; i < spanObjs.length; i++) { // 清空span背景 spanObjs[i].removeAttribute("class"); } // 设置当前span标签 spanObjs[pos].className = "current"; }; // 右移 rightObj.onclick = moveRight; function moveRight() { if (pos === spanObjs.length) { // 在到达克隆的一张的时候,立即跳到第一张 pos = 0; ulObj.style.left = 0 + "px"; } pos++; animation(ulObj, -pos * moveWidth); if (pos === spanObjs.length) { spanObjs[0].className = "current"; spanObjs[spanObjs.length - 1].className = ""; } else { for (var i = 0; i < spanObjs.length; i++) { // 清空span背景 spanObjs[i].removeAttribute("class"); } // 设置当前span标签 spanObjs[pos].className = "current"; } }; // 遍历所有的 span 标签 for (var i = 0; i < spanObjs.length; i++) { // 获取每个span的编号,设置自定义属性 spanObjs[i].setAttribute("index", i + ""); spanObjs[i].onmouseover = function () { for (var j = 0; j < spanObjs.length; j++) { // 清空span背景 spanObjs[j].removeAttribute("class"); } // 设置当前span标签 this.className = "current"; // 每个编号*移动的宽度就是移动到的目标位置 pos = this.getAttribute("index"); if (pos) { animation(ulObj, -pos * moveWidth); } else { } }; } // 封装动画移动函数 function animation(element, target) { // 判断当前的位置 var current = element.offsetLeft; var onestep = 7; var timeId = setInterval(function () { current += current < target ? onestep : -onestep; if (Math.abs(current - target) >= onestep) { element.style.left = current + "px"; } else { clearInterval(timeId); element.style.left = target + "px"; } }, 10); }</script></body></html>
1、首先获取所有需要的元素。
2、使用克隆第一个 li 标签来模拟从最后一个图片切换到第一个图片的过程。注意:这时候 ul 的宽度要改变,保证 li 的浮动在一行显示。
3、在右移最后一张过度到第二张的时候的处理方式为:当用户看到第一张的时候其实是最后一张,这个时候怎么过度到第二张?处理方法是,当在需要从最后一张跳转到第二张的时候,先让最后一张图切换到第一张,因为是克隆的,所以最后一张和第一张没有区别,用户看到的第一张其实是最后一张切换到了第一张,这个时候正常切换到第二张即可。
4、当需要点击左右切换按钮,需要数字按钮相对应的时候,注意第一个数字按钮和最后一个数字按钮的特殊处理。
5、图片下标 pos 是链接点击按钮和数字按钮的关键。
6、设置自动播放的时候,不使用定时器设置 pos 的方式,是因为当前 pos 的值不确定,使用自动点击右移按钮的方式。之所以设置两个 setInterval(moveRight, 1000); ,一个是进入页面自动播放,一个是鼠标退出 box 后的自动播放。
一、定时器
BOM 中有两中方式设置定时器。
1、方式一
特点:定时器可以重复使用。
// 参数有两个:// 第一个参数:定时器定时结束处理函数// 第二个参数:定时事件,单位毫秒。// 返回值:定时器id值var timeId = window.setInterval(function() { // ...}, 1000); // 定时1s// 清除定时器// 参数只有一个:定时器的 id 值。window.clearInterval(timeId);
1.1、案例:图片摇起来
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title> <style> div { position: absolute; } </style></head><body><input type="button" value="摇起来" id="btn1"><input type="button" value="停止" id="btn2"><div id="dv"> <img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="images/Daotin.png" alt=""></div><script class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="common.js"></script><script> var timeId = 0; my$("btn1").onclick = function () { timeId = setInterval(function () { //让图片动起来可以使div动起来 var x = parseInt(Math.random() * 100) + 1; // 1-100随机数 var y = parseInt(Math.random() * 100) + 1; my$("dv").style.left = x + "px"; my$("dv").style.top = y + "px"; }, 100); }; my$("btn2").onclick = function () { clearInterval(timeId); };</script></body></html>
点击”摇起来“按钮,图片每隔 100ms 动一次,点击停止按钮,图片停止移动。
遗留问题:
多次点击“摇起来”按钮的时候,图片动的越来越快,而且点击“停止”按钮没法停下来。
原因分析:
多次点击“摇起来”按钮的时候,timeId 的值会有多个,而停止的时候,只会清理最后一个值,其他的值对应的定时器没有清理。
解决方法:
在每次点击按钮的时候,先进行一次定时器的清理动作。clearInterval(timeId);
2、方式二
特点:定时器是一次性的。
setTimeout(); // 参数与返回值同 setInterval();
这个定时器只执行一次。虽然只执行一次,但是还是要清零,不然就一直占内存。
clearTimeOut(); // 参数为 setTimeout() 定时器的 id。
2.1、案例:协议禁用倒计时
<body><input type="button" value="请认真阅读协议(5)" id="btn" disabled><script class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="common.js"></script><script> var time = 5; var timeId = setInterval(function () { time--; if (time >= 0) { my$("btn").value = "请认真阅读协议(" + time + ")"; } else { clearInterval(timeId); my$("btn").value = "同意"; my$("btn").disabled = false; } }, 1000);</script></body>
倒计时后才可以点击同意按钮。
2.2、案例:移动元素
目标:有两个按钮,点击第一个按钮,div 缓慢移动到 400px 位置,点击第二个按钮缓慢移动到 800px 位置,再点击第一个按钮缓慢移动到 400px 位置......
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title> <style> * { margin: 0; padding: 0; } input { margin-top: 10px; } div { position: absolute; width: 200px; height: 100px; background-color: yellowgreen; margin-top: 10px; /*left: 20px;*/ } </style></head><body><input type="button" value="移动400px" id="btn1"><input type="button" value="移动800px" id="btn2"><div id="dv"></div><script class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="common.js"></script><script> // 移动400px my$("btn1").onclick = function () { animation(my$("dv"), 400); }; // 移动800px my$("btn2").onclick = function () { animation(my$("dv"), 800); }; // 封装动画移动函数 function animation(element, target) { // 判断当前的位置 var current = element.offsetLeft; // 不能使用 element.style.left var onestep = 7; var timeId = setInterval(function () { current += current < target ? onestep : -onestep; if (Math.abs(current - target) >= onestep) { element.style.left = current + "px"; } else { clearInterval(timeId); element.style.left = target + "px"; } }, 20); }</script></body></html>
1、既然要缓慢移动,就需要定时器。
2、当前位置的获取不能使用 element.style.left; 而需要使用 element.offsetLeft; 因为所有写在标签中的 style 属性值都拿不到,只有内联的 style 属性值可以使用 element.style.left 拿到。而 element.offsetLeft 则两种方式都可以拿到。
3、需要每次移动的步数 onestep,而且有回退的需要,所以 onestep 可能是负数。
4、每次移动后判断现在的位置到目标位置的距离,如果大于 onestep,那么就移动 当前 current 加减 onestep 的位置,否则就移动到目标位置,这样做的目的是避免 onestep 的不确定,导致最后的终点与目标还差少许的距离。
5、使用当前与目标距离的绝对值来决定是前进还是后退。
6、到达目标位置后,关闭定时器。
7、将动画过程封装成一个函数,参数为移动的目标和移动的距离。
8、注意:div 需要脱离文档流。
2.3、案例:轮播图
2.3.1、简单的轮播图
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title> <style> * { margin: 0; padding: 0; } #box { width: 400px; height: 250px; margin: 200px 0 0 400px; position: relative; border: 2px solid #31608a; overflow: hidden; } ul { width: 1300px; position: absolute; } li { list-style-type: none; float: left; } img { width: 400px; height: 250px; } li a { display: inline-block; } .sp { position: absolute; left: 50%; margin-left: -45px; bottom: 10px; } span { float: left; width: 20px; height: 20px; background-color: #fff; border-radius: 10px; text-align: center; font: 400 16px/20px Consolas; margin: 0 5px 0 5px; cursor: pointer; } .current { background-color: red; color: #fff; } </style></head><body><div id="box"> <ul> <li><a href="#"><img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="images/img1.jpg" alt=""></a></li> <li><a href="#"><img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="images/img2.jpg" alt=""></a></li> <li><a href="#"><img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="images/img3.jpg" alt=""></a></li> </ul> <div class="sp"> <span class="current">1</span> <span>2</span> <span>3</span> </div></div><script class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="common.js"></script><script> // 获取box元素 var boxObj = my$("box"); // 获取ul元素,因为移动的就是整个ul var ulObj = boxObj.children[0]; // 移动宽度 var moveWidth = document.getElementsByTagName("img")[0].offsetWidth; // 获取所有span标签 var spanObjs = boxObj.children[1].getElementsByTagName("span"); // console.log(spanObjs); for (var i = 0; i < spanObjs.length; i++) { // 获取每个span的编号,设置自定义属性 spanObjs[i].setAttribute("index", "" + i); spanObjs[i].onmouseover = function () { for (var j = 0; j < spanObjs.length; j++) { // 清空span背景 spanObjs[j].removeAttribute("class"); } // 设置当前span标签 this.className = "current"; // 每个编号*移动的宽度就是移动到的目标位置 var index = this.getAttribute("index"); animation(ulObj, -index*moveWidth); }; } // 封装动画移动函数 function animation(element, target) { // 判断当前的位置 var current = element.offsetLeft; var onestep = 7; var timeId = setInterval(function () { current += current < target ? onestep : -onestep; if (Math.abs(current - target) >= onestep) { element.style.left = current + "px"; } else { clearInterval(timeId); element.style.left = target + "px"; } }, 10); }</script></body></html>
1、移动的时候移动的是 ul,而不是单独的 li 或者 img。
2、span 小标签在鼠标进入的时候,背景变成红色。(排他事件:需要两步,第一清理所有,第二当前元素设置属性)
3、为每个 span 绑定事件时,程序开始,for 循环就运行完了,得不到每个span 标签的编号,所以要自定义属性保存每个 span 标签的编号。
4、直接调用封装好的动画移动函数来移动 ul 标签。
2.3.2、左右焦点轮播图
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title> <style> * { margin: 0; padding: 0; } #box { width: 400px; height: 250px; margin: 200px 0 0 400px; position: relative; border: 2px solid #31608a; overflow: hidden; } ul { width: 1300px; position: absolute; } li { list-style-type: none; float: left; } img { width: 400px; height: 250px; } .sp { width: 400px; height: 50px; position: absolute; top: 100px; display: none; } #left { width: 50px; height: 50px; float: left; cursor:pointer; text-align:center; font: 400 28px/50px Consolas; background-color: #fff; opacity: 0.4; /* 透明度 */ } #right { float: right; width: 50px; height: 50px; cursor:pointer; text-align:center; font: 400 28px/50px Consolas; background-color: #fff; opacity: 0.4; } </style></head><body><div id="box"> <ul> <li><a href="#"><img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="images/img1.jpg" alt=""></a></li> <li><a href="#"><img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="images/img2.jpg" alt=""></a></li> <li><a href="#"><img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="images/img3.jpg" alt=""></a></li> </ul> <div class="sp"> <span id="left"><</span> <span id="right">></span> </div></div><script class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="common.js"></script><script> // 获取box元素 var boxObj = my$("box"); // 获取ul元素,因为移动的就是整个ul var ulObj = boxObj.children[0]; // 移动宽度 var moveWidth = document.getElementsByTagName("img")[0].offsetWidth; // 获取sp标签 var spObj =boxObj.children[1]; // 获取span左标签 var leftObj = my$("left"); // 获取span右标签 var rightObj = my$("right"); var index = 0; boxObj.onmouseover = function () { spObj.style.display = "block"; }; boxObj.onmouseout = function () { spObj.style.display = "none"; }; // 左移 leftObj.onclick = function () { if(index) { index--; animation(ulObj, -index*moveWidth); } }; // 右移 rightObj.onclick = function () { if(index<ulObj.children.length-1) { index++; animation(ulObj, -index*moveWidth); } }; // 封装动画移动函数 function animation(element, target) { // 判断当前的位置 var current = element.offsetLeft; var onestep = 17; var timeId = setInterval(function () { current += current < target ? onestep : -onestep; if (Math.abs(current - target) >= onestep) { element.style.left = current + "px"; } else { clearInterval(timeId); element.style.left = target + "px"; } }, 10); }</script></body></html>
2.3.3、完整轮播图
需求:鼠标进入数字按钮自动切换;鼠标点击左右切换按钮切换,并且数字按钮跟着切换;自动轮播。
代码:
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="base.css"> <style> * { margin: 0; padding: 0; } #box { width: 400px; height: 250px; margin: 100px 0 0 400px; position: relative; border: 2px solid #31608a; overflow: hidden; } ul { width: 1300px; position: absolute; } li { list-style-type: none; float: left; } img { width: 400px; height: 250px; } .sp { position: absolute; left: 50%; margin-left: -45px; bottom: 10px; } span { float: left; width: 20px; height: 20px; background-color: #fff; border-radius: 10px; text-align: center; font: 400 16px/20px Consolas; margin: 0 5px 0 5px; cursor: pointer; } .spdiv { width: 400px; height: 50px; position: absolute; top: 100px; display: none; } #left { width: 50px; height: 50px; float: left; cursor: pointer; text-align: center; font: 400 28px/50px Consolas; color: #fff; background-color: rgba(255, 255, 255, 0.3); } #right { float: right; width: 50px; height: 50px; cursor: pointer; text-align: center; font: 400 28px/50px Consolas; color: #fff; background-color: rgba(255, 255, 255, 0.3); } .current { background-color: red; color: #fff; } </style></head><body><div id="box"> <ul> <li><a href="#"><img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="images/img1.jpg" alt=""></a></li> <li><a href="#"><img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="images/img2.jpg" alt=""></a></li> <li><a href="#"><img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="images/img3.jpg" alt=""></a></li> </ul> <div class="sp"> <span class="current">1</span> <span>2</span> <span>3</span> </div> <div class="spdiv"> <s id="left"><</s> <s id="right">></s> </div></div><script class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="common.js"></script><script> // 获取box元素 var boxObj = my$("box"); // 获取ul元素,因为移动的就是整个ul var ulObj = boxObj.children[0]; // 移动宽度 var moveWidth = document.getElementsByTagName("img")[0].offsetWidth; // 获取ul中所有的li var liObjs = ulObj.children; ulObj.appendChild(liObjs[0].cloneNode(true)); // 克隆第一个li,加入到ul中的最后 ulObj.style.width = ulObj.offsetWidth + moveWidth + "px"; // 重新设置ul的宽度 // 获取所有span标签 var spanObjs = boxObj.children[1].getElementsByTagName("span"); // console.log(spanObjs); // 获取spdiv标签 var spdivObj = boxObj.children[2]; // 获取span左标签 var leftObj = my$("left"); // 获取span右标签 var rightObj = my$("right"); var pos = 0; var myTimeId = setInterval(moveRight, 1000); // 自动播放 + 鼠标进入事件 boxObj.onmouseover = function () { spdivObj.style.display = "block"; clearInterval(myTimeId); }; boxObj.onmouseout = function () { spdivObj.style.display = "none"; myTimeId = setInterval(moveRight, 1000); }; // 左移 leftObj.onclick = function () { if (pos === 0) { pos = spanObjs.length; ulObj.style.left = -spanObjs.length * moveWidth + "px"; } pos--; animation(ulObj, -pos * moveWidth); for (var i = 0; i < spanObjs.length; i++) { // 清空span背景 spanObjs[i].removeAttribute("class"); } // 设置当前span标签 spanObjs[pos].className = "current"; }; // 右移 rightObj.onclick = moveRight; function moveRight() { if (pos === spanObjs.length) { // 在到达克隆的一张的时候,立即跳到第一张 pos = 0; ulObj.style.left = 0 + "px"; } pos++; animation(ulObj, -pos * moveWidth); if (pos === spanObjs.length) { spanObjs[0].className = "current"; spanObjs[spanObjs.length - 1].className = ""; } else { for (var i = 0; i < spanObjs.length; i++) { // 清空span背景 spanObjs[i].removeAttribute("class"); } // 设置当前span标签 spanObjs[pos].className = "current"; } }; // 遍历所有的 span 标签 for (var i = 0; i < spanObjs.length; i++) { // 获取每个span的编号,设置自定义属性 spanObjs[i].setAttribute("index", i + ""); spanObjs[i].onmouseover = function () { for (var j = 0; j < spanObjs.length; j++) { // 清空span背景 spanObjs[j].removeAttribute("class"); } // 设置当前span标签 this.className = "current"; // 每个编号*移动的宽度就是移动到的目标位置 pos = this.getAttribute("index"); if (pos) { animation(ulObj, -pos * moveWidth); } else { } }; } // 封装动画移动函数 function animation(element, target) { // 判断当前的位置 var current = element.offsetLeft; var onestep = 7; var timeId = setInterval(function () { current += current < target ? onestep : -onestep; if (Math.abs(current - target) >= onestep) { element.style.left = current + "px"; } else { clearInterval(timeId); element.style.left = target + "px"; } }, 10); }</script></body></html>
1、首先获取所有需要的元素。
2、使用克隆第一个 li 标签来模拟从最后一个图片切换到第一个图片的过程。注意:这时候 ul 的宽度要改变,保证 li 的浮动在一行显示。
3、在右移最后一张过度到第二张的时候的处理方式为:当用户看到第一张的时候其实是最后一张,这个时候怎么过度到第二张?处理方法是,当在需要从最后一张跳转到第二张的时候,先让最后一张图切换到第一张,因为是克隆的,所以最后一张和第一张没有区别,用户看到的第一张其实是最后一张切换到了第一张,这个时候正常切换到第二张即可。
4、当需要点击左右切换按钮,需要数字按钮相对应的时候,注意第一个数字按钮和最后一个数字按钮的特殊处理。
5、图片下标 pos 是链接点击按钮和数字按钮的关键。
6、设置自动播放的时候,不使用定时器设置 pos 的方式,是因为当前 pos 的值不确定,使用自动点击右移按钮的方式。之所以设置两个 setInterval(moveRight, 1000); ,一个是进入页面自动播放,一个是鼠标退出 box 后的自动播放。
共同学习,写下你的评论
评论加载中...
作者其他优质文章