轮播图的实现
结构搭建
.focus {
position: relative;
width: 721px;
height: 455px;
background-color: purple;
overflow: hidden;
}
.focus ul {
position: absolute; // 必须添加定位,否则无法运动
top: 0;
left: 0;
width: 600%; // 这里的ul需要设置得尽量宽,才能让图片在处在一行上
}
.focus ul li {
float: left;
}
.arrow-l,
.arrow-r {
display: none;
position: absolute;
top: 50%;
margin-top: -20px;
width: 24px;
height: 40px;
background: rgba(0, 0, 0, .3);
text-align: center;
line-height: 40px;
color: #fff;
font-family: 'icomoon';
font-size: 18px;
z-index: 2;
}
.arrow-r {
right: 0;
}
.circle {
position: absolute;
bottom: 10px;
left: 50px;
}
.circle li {
float: left;
width: 8px;
height: 8px;
/*background-color: #fff;*/
border: 2px solid rgba(255, 255, 255, 0.5);
margin: 0 3px;
border-radius: 50%;
/*鼠标经过显示小手*/
cursor: pointer;
}
<div class="focus fl">
<!-- 左侧按钮 -->
<a href="javascript:;" class="arrow-l"> < </a>
<!-- 右侧按钮 -->
<a href="javascript:;" class="arrow-r"> > </a>
<!-- 核心的滚动区域 -->
<ul>
<li>
<a href="#"><img src="upload/focus.jpg" alt=""></a>
</li>
<li>
<a href="#"><img src="upload/focus1.jpg" alt=""></a>
</li>
<li>
<a href="#"><img src="upload/focus2.jpg" alt=""></a>
</li>
<li>
<a href="#"><img src="upload/focus3.jpg" alt=""></a>
</li>
</ul>
<!-- 底部小圆点 -->
<ol class="circle">
<li></li>
</ol>
功能需求
1.左右按钮的显示与隐藏
var arrow_l = document.querySelector('.arrow-l');
var arrow_r = document.querySelector('.arrow-r');
var focus = document.querySelector('.focus');
// 1. 鼠标经过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';
});
2.根据图片张数动态生成小圆圈
思路:
1.首先得到ul里面图片的张数
2.利用for循环动态生成小圆圈,放入ol中
3.创建节点creatElement('li')
4.插入节点ol.appendChild(li)
5.第一个小圆圈需要添加current类
6.点击切换小圆圈
var ul = focus.querySelector('ul')
var ol = focus.querySelector('.circle')
// console.log(ul.children.length); // 4
for(let i = 0; i < ul.children.length; i++) {
// 创建一个li
var li = document.createElement('li')
// 把li插入到ol里面
ol.appendChild(li)
// 点击切换小圆圈底色:点击当前小圆圈,就添加current类,其余的小圆圈移除这个current类
//在生成小圆点的同时直接绑定点击事件
li.addEventListener('click', function() {
// 先把所有的li清除current类名
for(let i = 0; i < ol.children.length; i++) {
ol.children[i].className = ''
}
// 把当前的点击的li 设置为current类名
this.className = 'current'
})
}
// 把ol里面的第一个li设置类名为current
ol.children[0].className = 'current'
3.点击小圆圈滚动图片
思路:
1.利用animate.js动画函数,可参考:juejin.cn/post/703032…
2.使用动画函数的前提,该元素必须有定位
3.注意是ul移动而不是li
4.核心算法:点击某个小圆圈,ul移动的的距离 = 小圆圈的索引号 * 图片的宽度
5.此时需要知道小圆圈的索引号,我们可以在生成小圆圈的时候,给它设置一个自定义属性,点击的时候获取这个自定义属性
var ul = focus.querySelector('ul')
var ol = focus.querySelector('.circle')
for(let i = 0; i < ul.children.length; i++) {
var li = document.createElement('li')
// 记录当前小圆圈的索引号,通过自定义属性来做
li.setAttribute('index', i)
ol.appendChild(li)
li.addEventListener('click', function() {
for(let i = 0; i < ol.children.length; i++) {
ol.children[i].className = ''
}
this.className = 'current'
// 3.点击小圆圈,移动图片 移动的是ul
// ul的移动距离 = 小圆圈索引号 * 图片的宽度
// 获取当前li的索引号
var index = this.getAttribute('index')
// 图片的宽度 == foucus的宽度
var focusWidth = focus.offsetWidth
animate(ul,-index * focusWidth, 15)
})
}
ol.children[0].className = 'current'
4.点击右侧按钮图片滚动(无缝滚动)
思路:
1.声明一个变量num, 点击一次,自增1,ul移动的距离 = num * 图片的宽度
2.克隆第一张图片,放到ul最后面
var first = ul.children[0].cloneNode(true)
ul.appendChild(first)
3.无缝滚动原理;
(1)当图片滚动到克隆的最后一张图片时,让ul快速的,不做动画的跳到最左侧:left = 0
(2)同时num赋值为0,这时候num++, 变成1,所以显示第二张图片。
// 4.点击左侧按钮,图片滚动一张
var num = 0
arrow_r.addEventListener('click', function() {
// 如果走到了最后复制的一张图片,此时我们的ul要快速复原left = 0
if(num = ul.children.length - 1) {
ul.style.left = 0
num = 0
}
num++
var focusWidth = focus.offsetWidth
animate(ul, -num * focusWidth, 15)
})
5.点击右侧按钮,小圆点跟着改变
思路:
1.再声明一个变量circle,每次点击自增1。
2.但是图片有5张,小圆圈只有4个少一个,必须加一个判断条件,如果走到了最后一张图片(克隆的),重新复原为0
// 5.点击右侧按钮,小圆圈一起变化
circle++
// 如果circle == 4 说明走到了最后我们克隆的这张图片了, 我们就复原
if(circle == ol.children.length) {
circle = 0
}
// 先清除其余小圆圈的current类名
for(var i = 0; i < ol.children.length; i++) {
ol.children[i].className = ''
}
// 再留下当前小圆圈的current类名
ol.children[circle].className = 'current'
6.两个bug
bug1. 点击小圆圈显示某张图片后,再点击右侧按钮,无法按照正常顺序显示下一张图片。
原因:控制图片的num 和 点击小圆圈的index没有联系起来
解决:让点击的小圆圈索引号 index = num
bug2. 点击小圆圈显示某张图片后,再点击右侧按钮,小圆圈没有正常跳到下一个。
原因: 控制小圆圈移动的circle 和 点击小圆圈的index没有联系起来
解决; 让点击的小圆圈索引号 index = circle
li.addEventListener('click', function () {
for (let i = 0; i < ol.children.length; i++) {
ol.children[i].className = ''
}
this.className = 'current'
var index = this.getAttribute('index')
// bug1: index = num
num = index
// bug2: index = circle
circle = index
num = index
var focusWidth = focus.offsetWidth
animate(ul, -index * focusWidth, 15)
})
7.左侧按钮的实现
左侧按钮的实现和右侧按钮实现原理一样,但需要判断图片和小圆圈的临界情况。
arrow_l.addEventListener('click', function () {
// 如果是第一张图片,点击左侧按钮后,我们需要ul快速跳到最后一张图片
if (num == 0) {
num = ul.children.length - 1
ul.style.left = -num * focusWidth + 'px';
}
num--
var focusWidth = focus.offsetWidth
animate(ul, -num * focusWidth, 15)
// 点击左侧按钮,小圆圈一起变化
circle--
// 如果circle < 0 说明走到了第一张图片, 则小圆圈要改为第4个小圆圈 索引值为3
circle = circle < 0 ? ol.children.length - 1 : circle
circleChange()
})
8.自动播放功能
思路:
1.利用定时器setInterval()
2.自动播放功能,类似于点击了右侧按钮
3.此时可以使用手动调用右侧按钮点击事件 arrow_r.click()
var timer = setInterval(function() {
// 手动调用点击事件
arrow_r.click()
},2000)
4.鼠标经过focus就停止定时器
5.鼠标经过focus就开启定时器
focus.addEventListener('mouseenter', function () {
arrow_l.style.display = 'block'
arrow_r.style.display = 'block'
// 鼠标经过,关闭定时器
clearInterval(timer)
timer = null // 清除定时器变量
});
focus.addEventListener('mouseleave', function () {
arrow_l.style.display = 'none'
arrow_r.style.display = 'none'
// 鼠标离开,开启定时器
timer = setInterval(function() {
// 手动调用点击事件
arrow_r.click()
},2000)
});
9.节流阀
作用:防止轮播图连续点击左右按钮造成播放过快。
思路:当上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续点击
实现:利用回调函数,添加一个变量flag来控制,锁住函数和解锁函数
var flag = true
arrow_r.addEventListener('click', function () {
if (flag) {
flag = false // 关闭节流阀
if (num == ul.children.length - 1) {
ul.style.left = 0
num = 0
}
num++
var focusWidth = focus.offsetWidth
animate(ul, -num * focusWidth, 15, ()=> {
flag = true // 利用回调函数,等函数执行完成后,打开节流阀
})
circle++
circle = circle == ol.children.length ? circle = 0 : circle
circleChange()
}
})
总结
好了,以上就是实现轮播图的所有功能了,这个轮播图的功能算是比较完整的,大家通过学习可以复习到很多原生dom和bom的操作,包括定时器的使用,js的基础知识等等。可能对于刚接触前端的小伙伴会觉得难懂,可以按照上面的思路,把轮播图的功能拆分成一个个小模块来实现,自己多敲几遍,相信你一定可以学会滴,加油鸭! 以下附上完整代码:
var arrow_l = document.querySelector('.arrow-l');
var arrow_r = document.querySelector('.arrow-r');
var focus = document.querySelector('.focus')
// 1. 鼠标经过focus 就显示隐藏左右按钮
focus.addEventListener('mouseenter', function () {
arrow_l.style.display = 'block'
arrow_r.style.display = 'block'
// 鼠标经过,关闭定时器
clearInterval(timer)
timer = null // 清除定时器变量
});
focus.addEventListener('mouseleave', function () {
arrow_l.style.display = 'none'
arrow_r.style.display = 'none'
// 鼠标离开,开启定时器
timer = setInterval(function () {
// 手动调用点击事件
arrow_r.click()
}, 2000)
});
// 2.动态生成小圆圈,有几张图片,就生成几个小圆圈
var ul = focus.querySelector('ul')
var ol = focus.querySelector('.circle')
// console.log(ul.children.length);
for (let i = 0; i < ul.children.length; i++) {
// 创建一个li
var li = document.createElement('li')
// 记录当前小圆圈的索引号,通过自定义属性来做
li.setAttribute('index', i)
// 把li插入到ol里面
ol.appendChild(li)
// 点击切换小圆圈底色:点击当前小圆圈,就添加current类,其余的小圆圈移除这个current类
//在生成小圆点的同时直接绑定点击事件
li.addEventListener('click', function () {
// 先把所有的li清除current类名
for (let i = 0; i < ol.children.length; i++) {
ol.children[i].className = ''
}
// 把当前的点击的li 设置为current类名
this.className = 'current'
// 3.点击小圆圈,移动图片 移动的是ul
// ul的移动距离 = 小圆圈索引号 * 图片的宽度
// 获取当前li的索引号
var index = this.getAttribute('index')
// bug1: index = num
num = index
// bug2: index = circle
circle = index
// 图片的宽度 == foucus的宽度
var focusWidth = focus.offsetWidth
animate(ul, -index * focusWidth, 15)
})
}
// 把ol里面的第一个li设置类名为current
ol.children[0].className = 'current'
// 克隆第一张图片,放到ul最后面
var first = ul.children[0].cloneNode(true)
ul.appendChild(first)
// 4.点击左侧按钮,图片滚动一张
// 控制图片的移动
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
num = 0
}
num++
var focusWidth = focus.offsetWidth
animate(ul, -num * focusWidth, 15, () => {
flag = true // 利用回调函数,等函数执行完成后,打开节流阀
})
// 5.点击右侧按钮,小圆圈一起变化
circle++
// 如果circle == 4 说明走到了最后我们克隆的这张图片了, 我们就复原
circle = circle == ol.children.length ? circle = 0 : circle
circleChange()
}
})
// 7. 左侧侧按钮实现
arrow_l.addEventListener('click', function () {
if (flag) {
flag = false;
// 如果是第一张图片,点击左侧按钮后,我们需要ul快速跳到最后一张图片
if (num == 0) {
num = ul.children.length - 1
ul.style.left = -num * focusWidth + 'px';
}
num--
var focusWidth = focus.offsetWidth
animate(ul, -num * focusWidth, 15, () => {
flag = true;
})
// 5.点击右侧按钮,小圆圈一起变化
circle--
// 如果circle < 0 说明走到了第一张图片, 则小圆圈要改为第4个小圆圈 索引值为3
circle = circle < 0 ? ol.children.length - 1 : circle
circleChange()
}
})
// 将左右按钮相同的部分进行函数封装
function circleChange() {
// 先清除其余小圆圈的current类名
for (var i = 0; i < ol.children.length; i++) {
ol.children[i].className = ''
}
// 再留下当前小圆圈的current类名
ol.children[circle].className = 'current'
}
// 8.自动播放功能
var timer = setInterval(function () {
// 手动调用点击事件
arrow_r.click()
}, 2000)