网页轮播图详细教程
网页轮播图
1. 搭建框架

分为三个区域:(1)左右按钮 (2)滚动区域 (3)小圆区域
html代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, user-scalable=no,
initial-sale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<title></title>
<link rel="stylesheet" type="text/css" href="css/index.css" />
<script src="js/index.js"></script>
</head>
<body>
<div class="main">
<!-- 左按钮 -->
<a href="javascript:;" class="left"><</a>
<!-- 右按钮 -->
<a href="javascript:;" class="right">></a>
<!-- 滚动区 -->
<ul>
<li>
<a href="#"><img src="img/focus1.jpg" /></a>
</li>
<li>
<a href="#"><img src="img/focus2.jpg" /></a>
</li>
<li>
<a href="#"><img src="img/focus3.jpg" /></a>
</li>
<li>
<a href="#"><img src="img/focus4.jpg" /></a>
</li>
</ul>
<!-- 小圆 -->
<ol class="circle">
<li class="current"></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ol>
</div>
</body>
</html>
css代码
* {
padding: 0;
margin: 0;
}
ul,ol {
list-style: none;
}
a {
text-decoration: none;
}
.main {
position: relative;
width: 721px;
height: 455px;
margin: 100px auto;
}
.left,.right {
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-size: 18px;
}
.right {
right: 0;
}
.circle {
position: absolute;
bottom: 10px;
left: 50px;
}
.main ul {
width: 1000%;
}
.main ul li {
float: left;
}
.circle li {
float: left;
width: 8px;
height: 8px;
border: 2px solid orange;
margin: 0 3px;
border-radius: 50%;
/*鼠标经过显示小手*/
cursor: pointer;
}
.current {
background-color: orange;
}
为了方便观察,暂时选中第一个小圈
效果图如下:

2.功能需求
1. 鼠标经过轮播图模块,左右按钮显示,离开隐藏左右按钮
2. 点击右侧按钮一次,图片往左播放一张,以此类推,左侧按钮同理
3. 图片播放的同时,下面小圆跟随一起变化
4. 点击小圆圈,可以播放相应图片
5. 鼠标不经过轮播图,轮播图自动播放图片
6. 鼠标经过轮播图,自动播放停止
3.功能实现
因为js是写在外部的,所以要添加load事件,页面加载完毕再调用js
我们先来实现第一个需求,我们通过display和js事件来实现
分析:先隐藏左右按钮,然后通过js事件显示出来,离开通过js事件再隐藏回去
左右按钮css代码
.left,.right {
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-size: 18px;
}
js代码
window.addEventListener("load", function () {
//1.获取元素
var left = document.querySelector(".left");
var right = document.querySelector(".right");
var main = document.querySelector(".main");
//2.鼠标经过显示左右按钮
main.addEventListener("mouseenter", function () {
left.style.display = "block";
right.style.display = "block";
});
//3.鼠标离开隐藏左右按钮
main.addEventListener("mouseleave", function () {
left.style.display = "none";
right.style.display = "none";
});
});
效果图如下:

我们发现,小圆数量和图片的li数量是分开写的,如果后期增减图片修改代码时比较麻烦,所以我们可以优化小圆代码,实现小圆数量随图片li数量一致
分析:先清空ol里面的li,用js动态创建li,实现自动化的效果
创建li节点,用for循环,插入到ol里面去,选中li,类名变为current
js代码
//4.动态生成圆圈
var ul = main.querySelector("ul");
var ol = main.querySelector(".circle");
for (var i = 0; i < ul.children.length; i++) {
//创建一个li
var li = document.createElement("li");
//插入ol
ol.appendChild(li);
//排他思想
li.addEventListener("click", function () {
//所有li清除类名
for (var i = 0; i < ol.children.length; i++) {
ol.children[i].className = "";
}
//当前li设置current类名
this.className = "current";
});
}
//第一个小li设置为current
ol.children[0].className = "current";
效果图如下:

下面我们实现点击小圆图片滑动的效果
分析:用到之前封装过的动画函数animate.js
animate.js 代码:
function animate(obj, target, callback) {
// console.log(callback); callback = function() {} 调用的时候 callback()
// 先清除以前的定时器,只保留当前的一个定时器执行
clearInterval(obj.timer);
obj.timer = setInterval(function () {
// 步长值写到定时器的里面
// 把我们步长值改为整数 不要出现小数的问题
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();
}
}
// 把每次加 这个步长值改为一个慢慢变小的值 步长公式:(目标值 - 现在的位置) / 10
obj.style.left = obj.offsetLeft + step + "px";
}, 15);
}
引入animate.js文件,因为index.js依赖于animate.js文件,所以要写在index.js的上面
<script src="js/animate.js"></script>
<script src="js/index.js"></script>
给ul加定位,就可以使用封装好的动画函数了
.main ul{
position: absolute;
left: 0;
top: 0;
width: 1000%;
}
核心算法:点击某个小圆,让图片滚动小圆的索引号(创建自定义属性)乘以图片的宽度作为ul移动距离
//4.动态生成圆圈
var ul = main.querySelector("ul");
var ol = main.querySelector(".circle");
for (var i = 0; i < ul.children.length; i++) {
//创建一个li
var li = document.createElement("li");
// 记录当前小圆圈的索引号 通过自定义属性来做
li.setAttribute("index", i);
//插入ol
ol.appendChild(li);
//排他思想
li.addEventListener("click", function () {
//所有li清除类名
for (var i = 0; i < ol.children.length; i++) {
ol.children[i].className = "";
}
//当前li设置current类名
this.className = "current";
var index = this.getAttribute("index");
var mainWidth = main.offsetWidth;
animate(ul, -index * mainWidth);
});
}
效果图如下:

效果图发现,左右按钮没了,因为ul加了定位,设置左右按钮的层级为2就好了。
下面我们做点击右按钮播放图片的效果
分析:右侧按钮和点击小圆滚动图片的效果大同小异,声明一个变量,点击右按钮,自增1,乘以图片的宽度作为ul的滚动距离就好了
因为都用到了图片宽度,所以提出来当全局变量
js代码
// 6.点击右按钮,图片滚动一张
var num = 0;
right.addEventListener("click", function () {
num++;
animate(ul, -num * mainWidth);
});
图片不能一直滚动下去,要实现无缝滚动
分析:把ul的第一个li克隆一份放到ul的后面,当图片滚动到克隆的第一个图片时,让ul快速跳到左侧,left为0,同时num赋值为0
js代码
// 6.点击右按钮,图片滚动一张
var num = 0;
right.addEventListener("click", function () {
if (num == ul.children.length - 1) {
ul.style.left = 0;
num = 0;
}
num++;
animate(ul, -num * mainWidth);
});
我们发现小圆因为直接增加li多了一个,所以我们要优化代码,让js克隆一个li添加到ul后面
分析:克隆ul第一个li cloneNode() 加true 深克隆,复制里面的子节点 false 浅克隆,然后插入到ul
因为克隆写到了下面,所以效果图为4个小圆,为了更清晰,我们给main加一个overflowhidden
效果图如下:

下面我们做小圆跟随右按钮变化的效果
分析:我们可以单独设置一个变量控制小圆的变化,点击右侧按钮就自加,到克隆的第一张图调回0
js代码:
// 6.点击右按钮,图片滚动一张
var num = 0;
// circle 控制小圆圈的播放
var circle = 0;
right.addEventListener("click", function () {
if (num == ul.children.length - 1) {
ul.style.left = 0;
num = 0;
}
num++;
animate(ul, -num * mainWidth);
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";
});
效果图如下:

此时我们发现了一个bug,点击小圆后再点击右侧箭头不同步,因为它们是两个单独变量控制的
所以我们要优化js代码
// 当我们点击了某个小li 就要把这个li 的索引号给 num
num = index;
// 当我们点击了某个小li 就要把这个li 的索引号给 circle
circle = index;
这样就能随心所欲的圆点右箭头的点了
下面我们来做左侧按钮的功能
分析:与右侧按钮同理,只需要修改参数即可
// 8.左侧按钮
left.addEventListener("click", function () {
if (num == 0) {
num = ul.children.length - 1;
ul.style.left = -num * mainWidth + "px";
}
num--;
animate(ul, -num * mainWidth);
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";
});
左按钮与右按钮有相同的代码,我们可以封装起来调用
js代码
// 7.右侧按钮
right.addEventListener("click", function () {
if (num == ul.children.length - 1) {
ul.style.left = 0;
num = 0;
}
num++;
animate(ul, -num * mainWidth);
circle++;
if (circle == ol.children.length) {
circle = 0;
}
// 调用函数
circleChange();
});
// 8.左侧按钮
left.addEventListener("click", function () {
if (num == 0) {
num = ul.children.length - 1;
ul.style.left = -num * mainWidth + "px";
}
num--;
animate(ul, -num * mainWidth);
circle--;
if (circle < 0) {
circle = ol.children.length - 1;
}
// 调用函数
circleChange();
});
function circleChange() {
// 先清除其余小圆圈的current类名
for (var i = 0; i < ol.children.length; i++) {
ol.children[i].className = "";
}
// 留下当前的小圆圈的current类名
ol.children[circle].className = "current";
}
效果图如下:

接下来我们做最后一个功能:自动播放
分析:添加定时器,自动播放相当于点击了右侧按钮,右侧按钮事件已经写好,所以我们要用到手动调用右侧按钮点击事件 right.click()
js代码
// 自动播放轮播图
var timer = setInterval(function () {
//手动调用点击事件
right.click();
}, 2000);
效果图如下:

鼠标经过main开启定时器
鼠标离开main关闭定时器
js代码
//2.鼠标经过显示左右按钮
main.addEventListener("mouseenter", function () {
left.style.display = "block";
right.style.display = "block";
clearInterval(timer);
timer = null; // 清除定时器变量
});
//3.鼠标离开隐藏左右按钮
main.addEventListener("mouseleave", function () {
left.style.display = "none";
right.style.display = "none";
timer = setInterval(function () {
//手动调用点击事件
right.click();
}, 2000);
});
效果图如下:

4.节流阀
防止轮播图按钮连续点击造成播放过快
节流阀的目的:当上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续触发
核心思路:利用回调函数,添加一个变量来控制,锁住函数和解锁函数
设置一个变量 var flag = true;
if(flag){flag = fals; do something}
利用回调函数,动画执行完毕,flag = true
效果图如下:

5. 完整代码
html代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, user-scalable=no,
initial-sale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<title></title>
<link rel="stylesheet" type="text/css" href="css/index.css" />
<script src="js/animate.js"></script>
<script src="js/index.js"></script>
</head>
<body>
<div class="main">
<!-- 左按钮 -->
<a href="javascript:;" class="left"><</a>
<!-- 右按钮 -->
<a href="javascript:;" class="right">></a>
<!-- 滚动区 -->
<ul>
<li>
<a href="#"><img src="img/focus1.jpg" /></a>
</li>
<li>
<a href="#"><img src="img/focus2.jpg" /></a>
</li>
<li>
<a href="#"><img src="img/focus3.jpg" /></a>
</li>
<li>
<a href="#"><img src="img/focus4.jpg" /></a>
</li>
</ul>
<!-- 小圆 -->
<ol class="circle"></ol>
</div>
</body>
</html>
css代码
* {
padding: 0;
margin: 0;
}
ul,ol {
list-style: none;
}
a {
text-decoration: none;
}
.main {
position: relative;
width: 721px;
height: 455px;
margin: 100px auto;
overflow: hidden;
}
.left,.right {
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-size: 18px;
z-index: 2;
}
.right {
right: 0;
}
.circle {
position: absolute;
bottom: 10px;
left: 50px;
}
.main ul {
position: absolute;
left: 0;
top: 0;
width: 1000%;
}
.main ul li {
float: left;
}
.circle li {
float: left;
width: 8px;
height: 8px;
border: 2px solid orange;
margin: 0 3px;
border-radius: 50%;
/*鼠标经过显示小手*/
cursor: pointer;
}
.current {
background-color: orange;
}
js代码
window.addEventListener("load", function () {
//1.获取元素
var left = document.querySelector(".left");
var right = document.querySelector(".right");
var main = document.querySelector(".main");
var mainWidth = main.offsetWidth;
//2.鼠标经过显示左右按钮
main.addEventListener("mouseenter", function () {
left.style.display = "block";
right.style.display = "block";
clearInterval(timer);
timer = null; // 清除定时器变量
});
//3.鼠标离开隐藏左右按钮
main.addEventListener("mouseleave", function () {
left.style.display = "none";
right.style.display = "none";
timer = setInterval(function () {
//手动调用点击事件
right.click();
}, 2000);
});
//4.动态生成圆圈
var ul = main.querySelector("ul");
var ol = main.querySelector(".circle");
for (var i = 0; i < ul.children.length; i++) {
//创建一个li
var li = document.createElement("li");
// 记录当前小圆圈的索引号 通过自定义属性来做
li.setAttribute("index", i);
//插入ol
ol.appendChild(li);
//排他思想
li.addEventListener("click", function () {
//所有li清除类名
for (var i = 0; i < ol.children.length; i++) {
ol.children[i].className = "";
}
//当前li设置current类名
this.className = "current";
var index = this.getAttribute("index");
// 当我们点击了某个小li 就要把这个li 的索引号给 num
num = index;
// 当我们点击了某个小li 就要把这个li 的索引号给 circle
circle = index;
// 5. 点击小圆圈,移动ul
animate(ul, -index * mainWidth);
});
}
//第一个小li设置为current
ol.children[0].className = "current";
// 克隆第一张图片(li)放到ul 最后面
var first = ul.children[0].cloneNode(true);
ul.appendChild(first);
// 6.点击右按钮,图片滚动一张
var num = 0;
// circle 控制小圆圈的播放
var circle = 0;
var flag = true;
// 7.右侧按钮
right.addEventListener("click", function () {
if (flag) {
//关闭节流阀
flag = false;
if (num == ul.children.length - 1) {
ul.style.left = 0;
num = 0;
}
num++;
animate(ul, -num * mainWidth, function () {
//打开节流阀
flag = true;
});
circle++;
if (circle == ol.children.length) {
circle = 0;
}
// 调用函数
circleChange();
}
});
// 8.左侧按钮
left.addEventListener("click", function () {
if (flag) {
flag = false;
if (num == 0) {
num = ul.children.length - 1;
ul.style.left = -num * mainWidth + "px";
}
num--;
animate(ul, -num * mainWidth, function () {
flag = true;
});
circle--;
if (circle < 0) {
circle = ol.children.length - 1;
}
// 调用函数
circleChange();
}
});
function circleChange() {
// 先清除其余小圆圈的current类名
for (var i = 0; i < ol.children.length; i++) {
ol.children[i].className = "";
}
// 留下当前的小圆圈的current类名
ol.children[circle].className = "current";
}
// 自动播放轮播图
var timer = setInterval(function () {
//手动调用点击事件
right.click();
}, 2000);
});