JavaScript学习笔记—制作网页轮播图
一、 分析:
构成模块:
- 最外边一个大的div
- 里头一个ul ul里每个小li放一张图片 (核心的滚动区域)
- 左右两个按钮
- 小圆点
功能需求:
- 鼠标经过轮播图模块,显示左右按钮,离开隐藏左右按钮。
- 动态生成小圆圈 有几张图片,我们就生成几个小圆圈
- 当前的小li 设置current 类名 (排他思想)
- 点击小圆圈滚动图片,播放相应图片
- 点击右侧按钮一次,图片往左播放一张,以此类推,左侧按钮同理
- 图片播放的同时,下面小圆圈模块跟随一起变化。
- 鼠标不经过轮播图时,轮播图会自动播放图片。
- 鼠标经过,轮播图模块,自动播放停止。
二、 分步实现代码
step 1:
// 1.获取元素
var arrow_r=document.querySelector('.arrow-r');
var arrow_l=document.querySelector('.arrow-l');
var focus =document.querySelector('.focus');
// 2.鼠标经过focus 就显示隐藏左右按钮
focus.addEventListener('mouseenter',function(){
arrow_l.style.display='block';
arrow_r.style.display='block';
});
focus.addEventListener('mouseleave',function(){
arrow_l.style.display='none ';
arrow_r.style.display='none ';
});
step 2:动态生成小圆圈
分析:
- 核心思想:小圆圈的个数要跟图片张数一致
- 所以,首先先得到 ul 里面图片的张数(图片放入li里面,所以就是li的个数)
- 利用循环动态生成小圆圈(这个小圆圈要放入ol里面)
- 创建节点 creatElement(‘li’)
- 插入节点 ol.appendChild(li)
- 第一个小圆圈需要添加current类
代码段:
// 3.动态生成小圆圈 有几张图片,我们就生成几个小圆圈
var ul=focus.querySelector('ul');
var ol=focus.querySelector('ol');
for(var i=0;i<ul.children.length;i++){
// 创建一个小li
var li=document.createElement('li');
// 把小li插入到ol里面
ol.appendChild(li);
//把ol里面的第一个小li设置类名为current
ol.children[0].className='current';
step 3:
// 4.点击当前的小li 设置current 类名 (排他思想)
li.addEventListener('click',function(){
// 干掉所有人 把所有的小li 清除current类名
for (var i=0;i<ul.children.length ;i++){
ol.children[i].className='';
}
// 留下我自己 当前的小li 设置current 类名
this.className='current';
});
step 4:点击小圆圈滚动图片
分析:
- 此时用到animate动画函数,将js文件引入(注意:因为index.js依赖animate.js 所以,animate.js要写到index.js上面)
- 使用动画函数的前提,该元素必须有定位
- 注意是ul移动 而不是小li
- 滚动图片的核心算法:点击某个小圆圈,就让图片滚动 小圆圈的索引号乘以图片的宽度 做为ul移动距离
- 此时需要知道小圆圈的索引号,我们可以在生成小圆圈的时候,给他设置一个自定义属性,点击的时候就获取这个自定义属性即可。
代码段:
//记录当前小圆圈的索引号 通过自定义属性来做
li.setAttribute('index',i); //这里!!漏了
//5.点击小圆圈,移动图片 移动的是ul
//ul 的移动距离 小圆圈的索引号 乘以 图片的宽度 (注意:是负值)
//当我们点击了某个小li 就拿到当前小li的 索引号
var index=this.getAttrbute('index');
animate(ul,-index*focusWidth);
step 5-1:点击右侧按钮一次,图片往左播放一张
分析:
- 声明一个unm变量(专门控制),点击一次 自增1 让这个变量乘以图片宽度,就是ul 的滚动距离。
- 图片无缝滚动原理 (把 ul第一个li复制一份,放到ul 的最后面)
- 当图片滚动到克隆的最后一张图片时,让ul 快速的、不做动画的跳到最左侧:left为0
- 同时将unm赋值为0,可以从新开始滚动图片了
代码段:
//6.克隆第一张图片(li)放到ul 最后面
var first=ul.children[0].cloneNode(true);
ul.appendChild(first);
// 7.点击右侧按钮,图片滚动一张
var num=0;
arrow_r.addEventListener('click',function(){
//如果走到最后复制的一张图片,
//此时,我们的ul 要快速复原 left 改为 0
if (num==ul.children.length-1) {
ul.style.left=0 + 'px';
num=0;
}
num++;
animate(ul,-num*focusWidth);
});
step 5-2:点击左侧按钮一次,图片往右播放一张
同理
代码段:
arrow_l.addEventListener('click',function(){
if (num==0) {
num=ul.children.length-1;
ul.style.left= -num*focusWidth+'px';
}
num--;
animate(ul,-num*focusWidth); //这边也要负数!
});
step6-1 :小圆圈跟随右侧按钮一起变化
分析:
- 最简单的做法是在声明一个变量circle,每次点击自增1,(注意,左侧按钮也需要这个变量,因此要声明为全局变量。)
- 但是图片有5张,我们小圆圈只有4个少一个,必须加一个半段条件
- 如果circle==4 就从新复原为 0。
代码段:
// 8.点击右侧按钮,小圆圈跟随一起变化 可以在声明一个变量控制小圆圈的播放
circle++;
if(circle==ol.children.length){
circle=0;
}
for(var i=0;i<ol.children.length;i++){
// 先清除其余小圆圈的current类名
ol.children[i].className='';
}
// 留下当前的小圆圈的current类名
ol.children[circle].className='current';
});
step6-2 :小圆圈跟随左侧按钮一起变化
同理
代码段:
if (circle==0) {
circle=ol.children.length;
}
circle--; //这里!要放在判断之后(也可以改成判断circle<0 就不用放后面 关系不大)
for(var i=0;i<ol.children.length;i++){
ol.children[i].className='';
}
ol.children[circle].className='current';
step6-3 :将共有的一段代码封装起来,改成函数调用
function circleChange (){
for(var i=0;i<ol.children.length;i++){
// 先清除其余小圆圈的current类名
ol.children[i].className='';
}
// 留下当前的小圆圈的current类名
ol.children[circle].className='current';
}
step7 :修补两个bug
分析:
num、circle和index是独立的 所以存在小圆圈不按顺序的情况
因此
// 当我们点击了某个小li 就要把这个li 的索引号给 num
num=index;
// 当我们点击了某个小li 就要把这个li 的索引号给 circle
circle=index;
step8 :鼠标不经过轮播图时,轮播图会自动播放图片。
分析:
- 添加一个定时器
- 自动播放轮播图,实际就类似于点击了右侧按钮
- 此时我们使用手动调用右侧按钮点击事件 arrow_r.click()
代码段:
// 10.自动播放轮播图
var timer=setInterval(function(){
// 手动调用点击事件
arrow_r.click();
},2000);
step9 :防止轮播图按钮连续点击造成播放过快
分析:
- 节流阀的目的:当上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法接连触发。
- 核心实现思路:利用一个回调函数,添加一个变量来控制,锁住函数和解锁函数。
- 开始设置一个变量 var flag=true;
- if (flag){flag=false;do someing} 关闭水龙头
- 利用回调函数 动画执行完毕,flag=true 打开水龙头
代码段:
arrow_r.addEventListener('click',function(){
if(flag){
flag=false;//关闭节流阀
//如果走到最后复制的一张图片,此时,我们的ul 要快速复原left 改为 0
if (num==ul.children.length-1) {
ul.style.left=0+'px';
num=0;
}
num++;
animate(ul,-num*focusWidth,function(){
flag=true;//打开节流阀
});
// 8.点击右侧按钮,小圆圈跟随一起变化 可以在声明一个变量控制小圆圈的播放
circle++;
if(circle==ol.children.length){
circle=0;
}
circleChange();
}
});
二、 完整JS代码:
window.addEventListener('load',function(){
// 1.获取元素
var arrow_r=document.querySelector('.arrow-r');
var arrow_l=document.querySelector('.arrow-l');
var focus =document.querySelector('.focus');
var focusWidth=focus.offsetWidth;
// 2.鼠标经过focus 就显示隐藏左右按钮
focus.addEventListener('mouseenter',function(){
arrow_l.style.display='block';
arrow_r.style.display='block';
});
focus.addEventListener('mouseleave',function(){
arrow_l.style.display='none ';
arrow_r.style.display='none ';
});
// 3.动态生成小圆圈 有几张图片,我们就生成几个小圆圈
var ul=focus.querySelector('ul');
var ol=focus.querySelector('ol');
for(var i=0;i<ul.children.length;i++){
// 创建一个小li
var li=document.createElement('li');
//记录当前小圆圈的索引号 通过自定义属性来做
li.setAttribute('index',i); //这里!!漏了
// 把小li插入到ol里面
ol.appendChild(li);
// 4.点击当前的小li 设置current 类名 (排他思想)
li.addEventListener('click',function(){
// 干掉所有人 把所有的小li 清除current类名
for (var i=0;i<ol.children.length ;i++){
ol.children[i].className='';
}
// 留下我自己 当前的小li 设置current 类名
this.className='current';
//5.点击小圆圈,移动图片 移动的是ul
//ul 的移动距离 小圆圈的索引号 乘以 图片的宽度 (注意:是负值)
//当我们点击了某个小li 就拿到当前小li的 索引号
var index =this.getAttribute('index');
// 当我们点击了某个小li 就要把这个li 的索引号给 num
num=index;
// 当我们点击了某个小li 就要把这个li 的索引号给 circle
circle=index;
console.log(num);
console.log(circle);
console.log(index);
console.log(focusWidth);
animate(ul, -index * focusWidth);
})
}
//把ol里面的第一个小li设置类名为current
ol.children[0].className='current';
//6.克隆第一张图片(li)放到ul 最后面
var first=ul.children[0].cloneNode(true);
ul.appendChild(first);
// 7.点击右侧按钮,图片滚动一张
var num=0;
var circle=0;
var flag=true;
arrow_r.addEventListener('click',function(){
if(flag){
flag=false;//关闭节流阀
//如果走到最后复制的一张图片,此时,我们的ul 要快速复原left 改为 0
if (num==ul.children.length-1) {
ul.style.left=0+'px';
num=0;
}
num++;
animate(ul,-num*focusWidth,function(){
flag=true;//打开节流阀
});
// 8.点击右侧按钮,小圆圈跟随一起变化 可以在声明一个变量控制小圆圈的播放
circle++;
if(circle==ol.children.length){
circle=0;
}
circleChange();
}
});
// 9.左侧按钮做法
arrow_l.addEventListener('click',function(){
if(flag){
flag=false;
if (num==0) {
num=ul.children.length-1;
ul.style.left= -num*focusWidth+'px';
}
num--;
animate(ul,-num*focusWidth,function(){
flag=true;
}); //这边也要负数!
//点击左侧按钮,小圆圈跟随一起变化 可以再声明一个变量控制小圆圈的播放
//如果circle < 0 说明第一张图片,则小圆圈要改为第4个小圆圈(3)
if (circle==0) {
circle=ol.children.length;
}
circle--;
circleChange();
});
//简化代码,省得复制两次这个代码
function circleChange (){
for(var i=0;i<ol.children.length;i++){
// 先清除其余小圆圈的current类名
ol.children[i].className='';
}
// 留下当前的小圆圈的current类名
ol.children[circle].className='current';
}
// 10.自动播放轮播图
var timer=setInterval(function(){
// 手动调用点击事件
arrow_r.click();
},2000);
})
Leaning from pink 老师。
pink 老师说:“这个代码可能一辈子最多只会写一次”。所以我就认真的感受一下,记录一下,以后就直接ctrl+c&ctrl+v 啦~