布局:
slider > ul > li
slider > arrow > a> img
arrow : z-index:2 ;
注意,ul 里面放着所有轮播图的图片,所以 ul 的宽度必须足够大能够容纳所有图片,这里有4张图片,ul宽度设置为 600%
功能需求:
1,鼠标经过轮播图模块,左右按钮显示,离开隐藏左右按钮
slider.addEventListener(“mouseover",function(){ arrowLeft.style.display="block"; arrowRight.style.display="block"; }) slider.addEventListener("mouseout",function(){ arrowLeft.style.display="none"; arrowRight.style.display="none"; })
2,动态生成小圆圈
①:核心思路:小圆圈的个数要跟图片张数一致
②:所以首先先得到 ul 里面图片的张数(图片放入 li 中,所以就是 li 的个数)
③:利用循环动态生成小圆圈(这个小圆圈要放入 ol 里面)
④:创建节点 createElement("li")
⑤:插入节点:ol.appendChild (li)
⑥:第一个小圆圈需要添加 current 类
var ul=document.querySelector("ul"); var ol=document.querySelector(".circle"); var imgs=ul.children; for(var i=0; i<imgs.length; i++) { document.createElement("li"); ol.appendChild(li); }
ol.children[0].className="current";
3, 小圆圈的排他思想
①点击哪个小圆圈,哪个小圆圈就添加 " current " 类
②其余的小圆圈就移除这个 current 类
③注意:我们在刚才生成小圆圈的同时,就可以直接绑定这个点击事件了。
for(var i=0;i<imgs.length;i++) { var li=document.createElement("li"); ol.appendChild(li); li..addEventListener("click" , function(){ for(var j=0; j<ol.children.length; j++) { ol.children[j].className=" "; } this.className="current" ; }) } ol.children[0].className="current";
4,点击小圆圈滚动图片
①此时用到 animate动画函数,将 js 文件引入 (注意,因为 index.js 依赖 animate.js,所以, animate.js 要写到 index.js 上面)
②使用动画函数的前提,该元素必须有定位(ul)
③注意是 ul 移动,不是 小 li
④滚动图片的核心算法:点击某个小圆圈,就让图片滚动,小圆圈的索引号乘以图片的宽度 作为 ul 的移动距离
⑤此时需要知道小圆圈的索引号,我们可以下生成小圆圈的时候,给它设置一个自定义属性,点 击的时候获取这个自定义属性即可。
for(var i=0 ; i<imgs.length ; i++) { document.createElement("li"); ol.appendChild(li); li.setAttribute("index" , i); li.addEventListener("click", function(){ for(var j=0; j<ol.children.length; j++) { ol.children[j].className=""; } this.className="current"; var index=this.getAttribute("index"); var sliderWidth=slider.offsetWidth; animate(ul , -index*sliderWidth); }) } ol.children[0].className="current";
5,右侧按钮无缝滚动
①点击右侧按钮一次,就让图片滚动一张
②声明一个变量num , 点击一次,自增 1,让这个变量乘以图片宽度,就是 ul 的滚动距离
③图片无缝滚动原理:
把 ul 第一个 li 复制一份,放到 ul 的最后面,
当图片滚动到克隆的最后一张图片时,让ul快速的,不做动画的跳到最左侧:left 为0,
同时num赋值为0,可以从新开始滚动图片了。
④ 克隆第一张图片
克隆 ul 第一个 li , cloneNode( ) , 加 true 深克隆, 复制里面的子节点,false 浅克隆
添加到 ul 最后面 appendChild()
var imgLast=ul.children[0].cloneNode(true);
ul.appendChild(imgLast);
var num=0; arrowRight.addEventListener("click" , function(){ if(num==ul.children.length-1) { ul.style.left=0; num=0; } num++; animate(ul, -num*sliderWidth); })
//这里必须是先判断,再加加,再执行
6,小圆圈跟随右侧按钮一起变化
①最简单的 做法是再声明一个变量 circle , 每次点击自增 1,注意,左侧按钮也需要这个变量, 因此要声明全局变量
②但是图片有5张,小圆圈只有4个少一个,必须加一个判断条件,
③如果 circle==4 ,就重新复原为 0
var num=0; var circle=0; arrowRight.addEventListener("click", function(){ if(num==ul.children.length) { ul.style.left=0; num=0; } num++; animate(ul, -num*sliderWidth); circle++; //这里必须是先加加,再判断,再执行 if(circle==ol.children.length) { circle=0; } for(var i=0;i<ol.children.length;i++) { ol.children[i].className=""; } ol.children[circle].className="current"; })
7,到这一步,还有两个bug 需要解决
①当点击小圆圈让图片播放到第三张,下面的小圆圈停留在第三个(索引号等于2)的时候,点击右侧按钮,发现下一张图片并不是第4张图片,而是第二张图片
②原因就是点击右侧按钮的时候,num值与点击小圆圈时候的 circle 没有关系
③解决方法:点击小圆圈的时候,获取小圆圈当前的索引号,然后把小圆圈当前的索引号 circle 赋给 num ,这样再点击右侧按钮的时候,就可以在 circle 的基础上自增了。
④第二个bug :上面的bug解决之后,点击小圆圈让图片播放到第三张,再点击右侧按钮,图片可以顺利播放到第四张,但是下面的小圆圈却显示在第二个
⑤原因还是因为点击右侧按钮的时候,右侧按钮点击次数的索引号 num 与 之后点击小圆圈的 circle 没有建立联系
⑥解决方案就是,在点击右侧按钮的时候,获取右侧按钮点击次数当前的索引号,然后把当前的索引号赋给 circle,这样再点击小圆圈的时候,就可以在 num 的基础上 自增了。
li.addEventListener("click ,function(){ for(var j=0; j<ol.children.length;j++) { ol.children[j].className=""; } this.className="current"; var index=this.getAttribute("index"); num=index; circle=index; animate(ul, -index*sliderWIdth); })
8,左侧按钮功能制作,方法:直接将右侧按钮点击事件复制过来,修改里面的参数即可,注意一些参数的修改
arrowLeft.addEventListener(click, function(){ if(num==0) { ul.style.left= -(ul.children.length-1)*sliderWidth +"px"; num=ul.children.length-1; } num--; animate(ul , -num*sliderWidth); circle--; if(circle<0) { circle=ol.children.length-1; } for(var i=0;i<ol.children.length ; i++) { ol.childdren[i].className=" " ; } ol.children[circle].className="current"; })
9,代码优化
window.addEventListener("load",function(){ // alert(11); var slider=document.querySelector(".slider"); var arrowLeft=document.querySelector(".arrow-left"); var arrowRight=document.querySelector(".arrow-right"); var sliderWidth=slider.offsetWidth; //1,鼠标经过,左右按钮显示,鼠标离开,左右按钮隐藏 slider.addEventListener("mouseover",function(){ arrowLeft.style.display= "block"; arrowRight.style.display= "block"; }) slider.addEventListener("mouseout",function(){ arrowLeft.style.display= "none"; arrowRight.style.display= "none"; }) //2,动态生成小圆圈 var ul=document.querySelector("ul"); var imgs=ul.children; var ol=document.querySelector(".circle"); for(var i=0;i<imgs.length;i++) { var li=document.createElement("li"); li.setAttribute("index",i); //记录当前小圆圈的索引号,通过自定义属性来做 ol.appendChild(li); //3,小圆圈的排他思想,我们可以直接在生成小圆圈的同时直接绑定点击事件 li.addEventListener("click",function () { for(var j=0;j<ol.children.length;j++){ ol.children[j].className=""; } this.className = "current"; //4,点击小圆圈,移动图片,当然移动的是 ul ,ul 的移动距离=小圆圈的索引号乘以图片的宽度,注意是负值 var index=this.getAttribute("index");//当我们点击了某个小 li ,就拿到当前小 li 的索引号 //var sliderWidth=slider.offsetWidth; 下面右侧按钮点击事件也用到这个值,所以把它放到最上面 num=index; //当我们点击了某个小圆圈,就要把这个小圆圈的索引号给 num circle=index; //当我们点击了某个小圆圈,就要把这个小圆圈的索引号给circle animate(ul,-index*sliderWidth); }) } ol.children[0].className="current"; //5,点击右侧按钮,图片滚动一张 var imgLast=ul.children[0].cloneNode(true); //克隆第一张图片 ul.appendChild(imgLast); var num=0; var circle=0; arrowRight.addEventListener("click",function () { if (num==ul.children.length-1) { ul.style.left=0; num=0; } num++; animate(ul,-num*sliderWidth); //6,点击右侧按钮,小圆圈跟随一起变化,可以再声明一个变量控制小圆圈的播放 circle++; if (circle==ol.children.length) { circle=0; } // for(var i=0;i<ol.children.length;i++) // { // ol.children[i].className=""; // } // ol.children[circle].className="current";
这里可以封装成一个circleChange函数
circleChange(); })
//7,点击左侧按钮,图片滚动一张 arrowLeft.addEventListener("click",function () { if (num==0) { // ul.style.left = -(ul.children.length - 1)*sliderWidth + "px"; // num = ul.children.length - 1; 这里可以优化一下
num=ul.children.length -1
ul.style.left= -num*sliderWidth +"px";
}
num--;
animate(ul,-num*sliderWidth); //8,点击左侧按钮,小圆圈跟随一起变化,可以再声明一个变量控制小圆圈的播放
circle--;
if (circle<0) {
circle=ol.children.length-1;
}
// for(var i=0;i<ol.children.length;i++)
// {
// ol.children[i].className="";
// }
// ol.children[circle].className="current";
circleChange() })
function circleChange() {
for(var i=0;i<ol.children.length;i++) {
ol.children[i].className="";
}
ol.children[circle].className="current";
}
})
10,自动播放功能
①添加一个定时器
②自动播放轮播图,实际就类似于点击了右侧按钮
③此时我们使用手动调用右侧按钮点击事件 arrowRight.click();
④鼠标经过slider就停止定时器
⑤鼠标离开slider就开启定时器
window.addEventListener("load",function(){ // alert(11); var slider=document.querySelector(".slider"); var arrowLeft=document.querySelector(".arrow-left"); var arrowRight=document.querySelector(".arrow-right"); var sliderWidth=slider.offsetWidth; //1,鼠标经过,左右按钮显示,鼠标离开,左右按钮隐藏 slider.addEventListener("mouseover",function(){ arrowLeft.style.display= "block"; arrowRight.style.display= "block"; clearInterval(timer); }) slider.addEventListener("mouseout",function(){ arrowLeft.style.display= "none"; arrowRight.style.display= "none"; timer=setInterval(function () { arrowRight.click(); },1000); }) //2,动态生成小圆圈 var ul=document.querySelector("ul"); var imgs=ul.children; var ol=document.querySelector(".circle"); for(var i=0;i<imgs.length;i++) { var li=document.createElement("li"); li.setAttribute("index",i); //记录当前小圆圈的索引号,通过自定义属性来做 ol.appendChild(li); //3,小圆圈的排他思想,我们可以直接在生成小圆圈的同时直接绑定点击事件 li.addEventListener("click",function () { for(var j=0;j<ol.children.length;j++){ ol.children[j].className=""; } this.className = "current"; //4,点击小圆圈,移动图片,当然移动的是 ul ,ul 的移动距离=小圆圈的索引号乘以图片的宽度,注意是负值 var index=this.getAttribute("index");//当我们点击了某个小 li ,就拿到当前小 li 的索引号 //var sliderWidth=slider.offsetWidth; 下面右侧按钮点击事件也用到这个值,所以把它放到最上面 num=index; //当我们点击了某个小圆圈,就要把这个小圆圈的索引号给 num circle=index; //当我们点击了某个小圆圈,就要把这个小圆圈的索引号给circle animate(ul,-index*sliderWidth); }) } ol.children[0].className="current"; //5,点击右侧按钮,图片滚动一张 var imgLast=ul.children[0].cloneNode(true); //克隆第一张图片 ul.appendChild(imgLast); var num=0; var circle=0; arrowRight.addEventListener("click",function () { if (num==ul.children.length-1) { ul.style.left=0; num=0; } num++; animate(ul,-num*sliderWidth); //6,点击右侧按钮,小圆圈跟随一起变化,可以再声明一个变量控制小圆圈的播放 circle++; if (circle==ol.children.length) { circle=0; } // for(var i=0;i<ol.children.length;i++) // { // ol.children[i].className=""; // } // ol.children[circle].className="current"; circleChange(); }) //7,点击左侧按钮,图片滚动一张 arrowLeft.addEventListener("click",function () { if (num==0) { // ul.style.left = -(ul.children.length - 1)*sliderWidth + "px"; // num = ul.children.length - 1; num=ul.children.length-1; ul.style.left= -num*sliderWidth +"px"; } num--; animate(ul,-num*sliderWidth); //8,点击左侧按钮,小圆圈跟随一起变化,可以再声明一个变量控制小圆圈的播放 circle--; if (circle<0) { circle=ol.children.length-1; } // for(var i=0;i<ol.children.length;i++) // { // ol.children[i].className=""; // } // ol.children[circle].className="current"; circleChange() }) function circleChange() { for(var i=0;i<ol.children.length;i++) { ol.children[i].className=""; } ol.children[circle].className="current"; } //9,自动播放轮播图 var timer=setInterval(function () { arrowRight.click(); },1000); })
11, 节流阀
①防止轮播图按钮连续点击造成播放过快
②节流阀的目的:当上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连 续触发
③核心实现思路:利用回调函数,添加一个变量来控制,锁住函数和解锁函数
④开始设置一个 var flage=trur;
⑤ if ( flag) { flag=false ; do something } 关闭水龙头
⑥利用回调函数,动画执行完毕, flag = true 打开水龙头
window.addEventListener("load",function(){ // alert(11); var slider=document.querySelector(".slider"); var arrowLeft=document.querySelector(".arrow-left"); var arrowRight=document.querySelector(".arrow-right"); var sliderWidth=slider.offsetWidth; //1,鼠标经过,左右按钮显示,鼠标离开,左右按钮隐藏 slider.addEventListener("mouseover",function(){ arrowLeft.style.display= "block"; arrowRight.style.display= "block"; clearInterval(timer); }) slider.addEventListener("mouseout",function(){ arrowLeft.style.display= "none"; arrowRight.style.display= "none"; timer=setInterval(function () { arrowRight.click(); },1000); }) //2,动态生成小圆圈 var ul=document.querySelector("ul"); var imgs=ul.children; var ol=document.querySelector(".circle"); for(var i=0;i<imgs.length;i++) { var li=document.createElement("li"); li.setAttribute("index",i); //记录当前小圆圈的索引号,通过自定义属性来做 ol.appendChild(li); //3,小圆圈的排他思想,我们可以直接在生成小圆圈的同时直接绑定点击事件 li.addEventListener("click",function () { for(var j=0;j<ol.children.length;j++){ ol.children[j].className=""; } this.className = "current"; //4,点击小圆圈,移动图片,当然移动的是 ul ,ul 的移动距离=小圆圈的索引号乘以图片的宽度,注意是负值 var index=this.getAttribute("index");//当我们点击了某个小 li ,就拿到当前小 li 的索引号 //var sliderWidth=slider.offsetWidth; 下面右侧按钮点击事件也用到这个值,所以把它放到最上面 num=index; //当我们点击了某个小圆圈,就要把这个小圆圈的索引号给 num circle=index; //当我们点击了某个小圆圈,就要把这个小圆圈的索引号给circle animate(ul,-index*sliderWidth); }) } ol.children[0].className="current"; //5,点击右侧按钮,图片滚动一张 var imgLast=ul.children[0].cloneNode(true); //克隆第一张图片 ul.appendChild(imgLast); var num=0; var circle=0; var flag=true; //flag节流阀 arrowRight.addEventListener("click",function () { if (flag) { flag=false; //关闭节流阀 if (num==ul.children.length-1) { ul.style.left=0; num=0; } num++; animate(ul,-num*sliderWidth,function () { flag=true; }); //6,点击右侧按钮,小圆圈跟随一起变化,可以再声明一个变量控制小圆圈的播放 circle++; if (circle==ol.children.length) { circle=0; } // for(var i=0;i<ol.children.length;i++) // { // ol.children[i].className=""; // } // ol.children[circle].className="current"; circleChange(); } }) //7,点击左侧按钮,图片滚动一张 arrowLeft.addEventListener("click",function () { if (flag) { flag=false; if (num==0) { // ul.style.left = -(ul.children.length - 1)*sliderWidth + "px"; // num = ul.children.length - 1; num=ul.children.length-1; ul.style.left= -num*sliderWidth +"px"; } num--; animate(ul,-num*sliderWidth,function () { flag=true; }); //8,点击左侧按钮,小圆圈跟随一起变化,可以再声明一个变量控制小圆圈的播放 circle--; if (circle<0) { circle=ol.children.length-1; } // for(var i=0;i<ol.children.length;i++) // { // ol.children[i].className=""; // } // ol.children[circle].className="current"; circleChange() } }) function circleChange() { for(var i=0;i<ol.children.length;i++) { ol.children[i].className=""; } ol.children[circle].className="current"; } //9,自动播放轮播图 var timer=setInterval(function () { arrowRight.click(); },1000); })
12,完整代码:
①index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="index.css"> <script type="text/javascript" src="animate.js"></script> <script type="text/javascript" src="index.js"></script> </head> <body> <div class="slider"> <a href="javascript:;" class="arrow-left"><</a> <!--左侧按钮--> <a href="javascript:;" class="arrow-right">></a> <!--右侧按钮--> <ul> <li><a href=""><img src="images/01.jpg" alt=""></a></li> <li><a href=""><img src="images/02.jpg" alt=""></a></li> <li><a href=""><img src="images/03.jpg" alt=""></a></li> <li><a href=""><img src="images/04.jpg" alt=""></a></li> </ul> <ol class="circle"></ol> </div> </body> </html>
②index.css
*{ padding:0; margin:0; } a{ text-decoration:none; } ul, ol{ list-style:none; } .slider{ 721px; height:455px; background-color:purple; margin: 100px auto; position:relative; overflow: hidden; } .slider > ul{ position:absolute; top:0; left:0; 600%; } .slider > ul >li{ float:left; } .arrow-left, .arrow-right{ 24px; height:40px; background-color: rgba(0,0,0,0.3); position:absolute; top:50%; margin-top:-20px; z-index:2; text-align:center; line-height:40px; color:#fff; font-size:20px; display:none; } .arrow-left{ left:0; } .arrow-right{ right:0; } ol.circle{ position:absolute; bottom:10px; left:50px; } .circle > li{ float:left; 8px; height:8px; border:2px solid rgba(255,255,255,0.5); margin:0 3px; border-radius:50%; cursor:pointer; } .current{ background-color: #fff; }
③index.js
window.addEventListener("load",function(){ // alert(11); var slider=document.querySelector(".slider"); var arrowLeft=document.querySelector(".arrow-left"); var arrowRight=document.querySelector(".arrow-right"); var sliderWidth=slider.offsetWidth; //1,鼠标经过,左右按钮显示,鼠标离开,左右按钮隐藏 slider.addEventListener("mouseover",function(){ arrowLeft.style.display= "block"; arrowRight.style.display= "block"; clearInterval(timer); }) slider.addEventListener("mouseout",function(){ arrowLeft.style.display= "none"; arrowRight.style.display= "none"; timer=setInterval(function () { arrowRight.click(); },1000); }) //2,动态生成小圆圈 var ul=document.querySelector("ul"); var imgs=ul.children; var ol=document.querySelector(".circle"); for(var i=0;i<imgs.length;i++) { var li=document.createElement("li"); li.setAttribute("index",i); //记录当前小圆圈的索引号,通过自定义属性来做 ol.appendChild(li); //3,小圆圈的排他思想,我们可以直接在生成小圆圈的同时直接绑定点击事件 li.addEventListener("click",function () { for(var j=0;j<ol.children.length;j++){ ol.children[j].className=""; } this.className = "current"; //4,点击小圆圈,移动图片,当然移动的是 ul ,ul 的移动距离=小圆圈的索引号乘以图片的宽度,注意是负值 var index=this.getAttribute("index");//当我们点击了某个小 li ,就拿到当前小 li 的索引号 //var sliderWidth=slider.offsetWidth; 下面右侧按钮点击事件也用到这个值,所以把它放到最上面 num=index; //当我们点击了某个小圆圈,就要把这个小圆圈的索引号给 num circle=index; //当我们点击了某个小圆圈,就要把这个小圆圈的索引号给circle animate(ul,-index*sliderWidth); }) } ol.children[0].className="current"; //5,点击右侧按钮,图片滚动一张 var imgLast=ul.children[0].cloneNode(true); //克隆第一张图片 ul.appendChild(imgLast); var num=0; var circle=0; var flag=true; //flag节流阀 arrowRight.addEventListener("click",function () { if (flag) { flag=false; //关闭节流阀 if (num==ul.children.length-1) { ul.style.left=0; num=0; } num++; animate(ul,-num*sliderWidth,function () { flag=true; }); //6,点击右侧按钮,小圆圈跟随一起变化,可以再声明一个变量控制小圆圈的播放 circle++; if (circle==ol.children.length) { circle=0; } circleChange(); } }) //7,点击左侧按钮,图片滚动一张 arrowLeft.addEventListener("click",function () { if (flag) { flag=false; if (num==0) { num=ul.children.length-1; ul.style.left= -num*sliderWidth +"px"; } num--; animate(ul,-num*sliderWidth,function () { flag=true; }); //8,点击左侧按钮,小圆圈跟随一起变化,可以再声明一个变量控制小圆圈的播放 circle--; if (circle<0) { circle=ol.children.length-1; } circleChange() } }) function circleChange() { for(var i=0;i<ol.children.length;i++) { ol.children[i].className=""; } ol.children[circle].className="current"; } //9,自动播放轮播图 var timer=setInterval(function () { arrowRight.click(); },1000); })
④animate.js
function animate(obj, target, callback) { // console.log(callback); callback = function() {} 调用的时候 callback() // 先清除以前的定时器,只保留当前的一个定时器执行 clearInterval(obj.timer); obj.timer = setInterval(function() { // 步长值写到定时器的里面 // 把我们步长值改为整数 不要出现小数的问题 // var step = Math.ceil((target - obj.offsetLeft) / 10); var step = (target - obj.offsetLeft) / 10; step = step > 0 ? Math.ceil(step) : Math.floor(step); if (obj.offsetLeft == target) { // 停止动画 本质是停止定时器 clearInterval(obj.timer); // 回调函数写到定时器结束里面 // if (callback) { // // 调用函数 // callback(); // } callback && callback(); } // 把每次加1 这个步长值改为一个慢慢变小的值 步长公式:(目标值 - 现在的位置) / 10 obj.style.left = obj.offsetLeft + step + 'px'; }, 15); }