轮播图案例
(1)、搭建轮播图的结构
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>轮播图结构</title>
<!-- <script src="../js/tools.js"></script> -->
<script src="../js/animation.js"></script>
<script src="./01.轮播图.js"></script>
<style>
* {
padding: 0;
margin: 0;
list-style: none;
text-decoration: none;
}
#outer {
width: 590px;
height: 470px;
border: 10px solid red;
margin: 50px auto;
position: relative;
overflow: hidden;
}
#outer > ul {
width: 500%;
position: absolute;
left: 0;
top: 0;
}
#outer > ul > li {
float: left;
}
.dot {
position: absolute;
bottom: 30px;
left: 50%;
transform: translate(-50%, -50%);
}
.dot > a {
display: inline-block;
width: 15px;
height: 15px;
border-radius: 50%;
background-color: #999;
margin: 0 5px;
}
.dot > .active,
.dot > a:hover {
background-color: orange;
}
.prev,
.next {
width: 40px;
height: 40px;
background-color: rgba(0, 0, 0, 0.4);
text-align: center;
position: absolute;
font-size: 30px;
color: #999;
/* 隐藏左右按钮 */
display: none;
}
.prev > a,
.next > a {
color: #fff;
}
.prev {
left: 10px;
top: 42%;
}
.next {
right: 10px;
top: 42%;
}
</style>
</head>
<body>
<div id="outer">
<!-- 图片部分 -->
<ul>
<li>
<a href="#"><img src="./img/1.jpg" alt="" /></a>
</li>
<li>
<a href="#"><img src="./img/2.jpg" alt="" /></a>
</li>
<li>
<a href="#"><img src="./img/3.jpg" alt="" /></a>
</li>
<li>
<a href="#"><img src="./img/4.jpg" alt="" /></a>
</li>
<!-- <li>
<a href="#"><img src="./img/1.jpg" alt="" /></a>
</li> -->
</ul>
<!-- 导航点 class="active"-->
<div class="dot">
<!-- <a href="#" ></a>
<a href="#"></a>
<a href="#"></a>
<a href="#"></a> -->
</div>
<!-- 左右导航 -->
<ol class="prevNext">
<li class="prev">
<a href="#"> <</a>
</li>
<li class="next">
<a href="#">></a>
</li>
</ol>
</div>
</body>
</html>
(2)、es5写法
功能需求:
- 鼠标经过轮播图模块,左右按钮显示,离开隐藏左右按钮
- 点击右侧按钮一次,图片往左播放一张,以此类推,左侧按钮同理
- 图片播放的同时,下面的小圆圈模块跟随一起变化
- 点击小圆圈,可以播放相应图片
- 鼠标不经过轮播图,轮播图也会自动播放图片
- 鼠标经过,轮播图模块,自动播放停止
window.addEventListener("load", function () {
var prev = this.document.querySelector(".prev");
var next = this.document.querySelector(".next");
var outer = this.document.querySelector("#outer");
//需求1 鼠标移入,左右按钮出现隐藏
outer.addEventListener("mouseenter", function () {
prev.style.display = "block";
next.style.display = "block";
});
outer.addEventListener("mouseleave", function () {
prev.style.display = "none";
next.style.display = "none";
});
//需求2 动态生成pot,小圆圈
// 2.1、获取元素
var ulL = outer.querySelector("ul");
var dot = outer.querySelector(".dot");
for (var i = 0; i < ulL.children.length; i++) {
// 2.2、动态的创建a标签
var a = this.document.createElement("a");
// 给a添加索引,方便下面计算点击圆圈,移动图片
a.setAttribute("index", i);
// 2.3 插入节点
dot.appendChild(a);
}
// 2.4 给第一个小点,设置选中样式
dot.children[0].className = "active";
//需求3 给点击的小圆圈加上类名 active 排他思想
var as = dot.querySelectorAll("a");
for (var i = 0; i < as.length; i++) {
as[i].addEventListener("click", function () {
for (var j = 0; j < as.length; j++) {
dot.children[j].className = "";
}
this.className = "active";
//需求4 点击小圆圈,移动图片 move(obj, attr, target, speed, callback)
//4.1 获取点击a的索引,这个索引是创建a时添加的,用来表示每个a
var index = this.getAttribute("index");
// 4.2 ulL的移动距离,小圆圈的索引号*图片的宽度
animation(ulL, -index * 590);
// move(ulL, "left", -index * 590, 10);
// 获取到index后,需要同步赋值给下面的num跟current
// 以便可以同步小圆点,跟点击下一张的变化
num = index;
current = index;
});
}
// 克隆第一张图片,不在结构里加
// 循环生成小圆点的时候,还没有克隆这个图片。所有不会自动生成的小圆圈
var firstImg = ulL.children[0].cloneNode(true);
ulL.appendChild(firstImg);
//需求5 点击左右按钮,实现上下一张切换
var num = 0;
var current = 0; //用来标记小圆圈
next.addEventListener("click", function () {
//无缝滚动 如果走到了最后一张图片,此时我们的ul要快速复原left改为0
if (num >= ulL.children.length - 1) {
ulL.style.left = 0;
num = 0;
}
num++;
animation(ulL, -num * 590);
// move(ulL, "left", -num * 590, 20);
// 点击右侧按钮,小圆圈跟着跳动
current++;
// 如果curent的数值跟小圆圈的数量一样,走到了克隆的那张图片,要还原为0
if (current == dot.children.length) {
current = 0;
}
for (var i = 0; i < dot.children.length; i++) {
dot.children[i].className = "";
}
dot.children[current].className = "active";
});
//需求6 左侧按钮的功能
prev.addEventListener("click", function () {
if (num == 0) {
num = ulL.children.length - 1;
ulL.style.left = -num * 590 + "px";
}
num--;
animation(ulL, -num * 590);
// move(ulL, "left", -num * 590, 20);
// 点击右侧按钮,小圆圈跟着跳动
current--;
// 如果curent的数值跟小圆圈的数量一样,要还原为0
if (current < 0) {
current = dot.children.length - 1;
}
for (var i = 0; i < dot.children.length; i++) {
dot.children[i].className = "";
}
dot.children[current].className = "active";
});
//需求7 自动播放功能
var timer = setInterval(function () {
// 手动调用点击事件
next.click();
}, 2000);
//需求8 鼠标移入,自动播放停止
outer.addEventListener("mouseenter", function () {
clearInterval(timer);
timer = null;
});
//需求9 鼠标移出,重新开启定时器
outer.addEventListener("mouseleave", function () {
timer = setInterval(function () {
// 手动调用点击事件
next.click();
}, 2000);
});
});
(3)、es6写法
/*
功能需求:
- 鼠标经过轮播图模块,左右按钮显示,离开隐藏左右按钮
- 点击右侧按钮一次,图片往左播放一张,以此类推,左侧按钮同理
- 图片播放的同时,下面的小圆圈模块跟随一起变化
- 点击小圆圈,可以播放相应图片
- 鼠标不经过轮播图,轮播图也会自动播放图片
- 鼠标经过,轮播图模块,自动播放停止
-无缝切换
*/
window.addEventListener('load',function(){
let that;
class swiper{
constructor(){
that=this;
this.imgList=document.querySelector('.imgList');
this.dotList=document.querySelector('.dot');
//获取图片的大小
this.imgWidth=this.imgList.children[0].offsetWidth;
//获取左右导航按钮
this.leftBtn=document.querySelector('.prev');
this.rightBtn=document.querySelector('.next');
this.outer=document.querySelector('#outer');
this.num=0;//图片索引
this.currentdot=0;//当前圆点索引
this.timer=null;
this.autoPlay();
this.crrateDot();
this.cloneImg();
this.addevent()
}
addevent(){
this.dotList.addEventListener('click',this.clickDot)
this.dotList.addEventListener('click',this.clickDotchangeImg)
// 鼠标经过轮播图模块,左右按钮显示,离开隐藏左右按钮
this.outer.addEventListener('mouseenter',this.showBtn)
this.outer.addEventListener('mouseleave',this.hideBtn)
//鼠标经过,轮播图模块,自动播放停止
this.outer.addEventListener('mouseenter',this.outplay)
this.outer.addEventListener('mouseleave',this.inplay)
//点击右侧按钮一次,图片往左播放一张,以此类推,左侧按钮同理
this.rightBtn.addEventListener('click',this.nextImg)
this.leftBtn.addEventListener('click',this.prevImg)
}
//各种事件
//创建小圆点
crrateDot(){
let imgNum = this.imgList.children.length;
console.log(imgNum);
for(let i=0;i<imgNum;i++){
let str="";
str=`
<a href="#" index="${i}"></a>
`
this.dotList.innerHTML+=str;
}
// 默认给第一个圆点添加active类
this.dotList.children[0].className="active";
console.log(this.dotList);
}
//点击小圆点颜色高亮并切换图片
clickDot(e){
// 阻止默认行为
e.preventDefault();
// 颜色高亮
console.log(e.target.nodeName)
if(e.target.nodeName=='A'){
let dots=that.dotList.children;
for(let i=0;i<dots.length;i++){
dots[i].className="";
}
e.target.className="active";
}
}
//切换图片
clickDotchangeImg(e){
let index=e.target.getAttribute("index");
console.log(index);
animation(that.imgList,-index*that.imgWidth)
}
//鼠标经过轮播图模块,左右按钮显示,离开隐藏左右按钮
//出现左右按钮
showBtn(){
that.leftBtn.style.display="block";
that.rightBtn.style.display="block";
}
// x隐藏左右按钮
hideBtn(){
that.leftBtn.style.display="none";
that.rightBtn.style.display="none";
}
//点击右侧按钮一次,图片往左播放一张
nextImg(){
if(that.num<that.imgList.children.length-1){
that.num++;
}else{
that.imgList.style.left=0;
that.num=1;
}
animation(that.imgList,-that.num*that.imgWidth);
let dotsLength=that.dotList.children.length;
if(that.currentdot<dotsLength-1){
that.currentdot++;
}else{
that.currentdot=0;
}
that.changeColor()
}
//点击左侧按钮一次,图片往右播放一张
prevImg(){
if(that.num>0){
that.num--;
}else{
that.imgList.style.left=-(that.imgList.children.length-2)*that.imgWidth+'px';
that.num=that.imgList.children.length-2;
}
animation(that.imgList,-that.num*that.imgWidth)
let dotsLength=that.dotList.children.length;
if(that.currentdot>0){
that.currentdot--;
}else{
that.currentdot=that.dotList.children.length-1;;
}
that.changeColor()
}
//按钮点击小圆点颜色高亮,
changeColor(){
let dots=that.dotList.children;
for(let i=0;i<dots.length;i++){
dots[i].className="";
}
dots[that.currentdot].className="active";
}
//轮播图自动播放
autoPlay(){
that.timer=setInterval(function(){
that.nextImg();
},1000)
}
//鼠标经过,轮播图模块,自动播放停止
outplay(){
clearInterval(that.timer);
}
//input输入框内容变化,轮播图自动播放
inplay(){
that.autoPlay();
}
//实现无缝滚动效果
cloneImg(){
let fistimg=that.imgList.children[0].cloneNode(true);
console.log(fistimg);
that.imgList.appendChild(fistimg);
}
}
new swiper()
})
(4)、节流阀优化
防止轮播图按钮连续点击造成播放过快
节流阀目的,当上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续触发
核心实现思路:利用回调函数,添加一个变量来控制,锁住函数和解锁函数
开始设置一个变量 var flag =true
if(flag){ flag = false,do something} 关闭水龙头
利用回调函数动画执行完毕, falg=true 打开水龙头
// 10、节流阀优化点击过快问题
var flag = true;
next.addEventListener("click", function () {
if (flag) {
flag = false; // 关闭水龙头
//无缝滚动 如果走到了最后一张图片,此时我们的ul要快速复原left改为0
if (num >= ulL.children.length - 1) {
ulL.style.left = 0;
num = 0;
}
num++;
animation(ulL, -num * 590, function () {
flag = true;
});
// move(ulL, "left", -num * 590, 20);
// 点击右侧按钮,小圆圈跟着跳动
current++;
// 如果curent的数值跟小圆圈的数量一样,走到了克隆的那张图片,要还原为0
if (current == dot.children.length) {
current = 0;
}
for (var i = 0; i < dot.children.length; i++) {
dot.children[i].className = "";
}
dot.children[current].className = "active";
}
});
//需求6 左侧按钮的功能
prev.addEventListener("click", function () {
if (flag) {
flag = false;
if (num == 0) {
num = ulL.children.length - 1;
ulL.style.left = -num * 590 + "px";
}
num--;
animation(ulL, -num * 590, function () {
flag = true;
});
// move(ulL, "left", -num * 590, 20);
// 点击右侧按钮,小圆圈跟着跳动
current--;
// 如果curent的数值跟小圆圈的数量一样,要还原为0
if (current < 0) {
current = dot.children.length - 1;
}
for (var i = 0; i < dot.children.length; i++) {
dot.children[i].className = "";
}
dot.children[current].className = "active";
}
});