效果图
1、从右向左循环滑动
2、可通过左右两端的箭头切换图片(有滑动效果)
3、可底部的小圆圈切换到指定图片(没有滑动效果)
4、图片切换,底部的小圆圈的样式会自动跟着改变
5、鼠标悬停在上面,会停止自动滑动。移除,会自动恢复自动滑动
前言
食用前必看
1、本博客适用人群:有css基础,对jQuery有基本的了解(我也是初学jQuery)
2、如果你使用的素材图大小不一样,自行修改代码中的有关地方。这几张图片我是从慕课网的首页扣下来的。在本博客的末尾,我也贴出来,方便各位拷贝下来。
分析
实现这个轮播图,有一个最关键的难点!这里我分析如何解决这个关键点的原理,其他的坑和注意的点以及容易混乱的细节,我都已经在代码中加上了详细的注释。在明白这个“如何解决这个难点”之后,可直接去结合注释分析代码。
假设,我们轮播显示的只有4张图,这4张图从右向左滑动。滑动一张图后,停留一会,再滑动下面一张。
那么问题是:当前已经显示的是第4张图,如何从第4张图【滑】回到第1张图(看起来好像无缝衔接)?注意,这里是【滑】回,而不是闪现回到第1张的位置。如果是闪现回到第1张的位置,直接通过设置ul的marginLeft即可实现。
我们可以将第1张图复制一份放到最后(就是说第5张图是第1张图的副本)。假设当前正在显示第4张图,然后第4张图滑动到第5张图。此时第4张图【滑】回到第1张图的动画我们已经看到了,虽然是第1张图的副本,但是视觉上就像是是:第4张图【滑】回到第1张图。此时显示的是第5张图(第1张的副本),此时来个【偷梁换柱】,通过设置ul的marginLeft闪回到真正的第1张的位置。由于副本和第1张一模一样,所以这个【闪回】在视觉上是感受不到的。
如何从第1张【滑】回到第4张呢?
在上面分析了:如何从第4张滑回到第1张,那么“如何从第1张【滑】回到第4张”的道理也是一样的。
假设当前显示的就是第1张,我点击了左端的 “<”。此时来个【偷梁换柱】,通过设置ul的marginLeft一瞬间切换到第5张图(第1张的副本),由于副本和第1张一模一样,所以这个闪现在视觉上是感受不到的。那么再从第1张的副本滑动第4张。那么在视觉上就好像是第1张【滑】回到第4张的假象了。
明白这个原理,就已经成功了一半。剩下就是代码实现,但是这个代码的不少细节都要考虑的比较【细致】,大家可以多多尝试。
代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>轮播图 by passerbyYSQ</title>
<script src="js/jQuery1.4.2.js"></script>
<!-- coded by passerbyYSQ -->
<style>
* {
margin: 0px;
padding: 0px;
list-style: none;
}
#banner {
width: 936px; /* 刚好为图片真实宽度的一半 */
height: 382px; /* 刚好为图片真实高度的一半 */
margin: 50px auto;
border-radius: 20px;
overflow: hidden;
/* border: 1px #000 solid; */ /* 加上边框便于观察 */
position: relative;
}
#banner #bg img {
width: 936px; /* 图片高度也等比缩小 */
}
#banner li {
float: left;
}
#banner #aList li {
width: 20px;
height: 20px;
border-radius: 10px;
background: rgba(0, 0, 0, 0.5);
float: left;
margin: 0px 5px;
}
#banner #aList li:hover {
cursor: pointer;
}
#banner #aList {
position: absolute;
bottom: 10px;
left: 50%;
/* margin-left: -60px; */
}
#banner .left, #banner .right {
width: 50px;
height: 50px;
border-radius: 25px;
background: rgba(0, 0, 0, 0.2);
position: absolute;
top: 50%;
margin-top: -25px;
font-size: 35px;
font-family: bold;
color: rgba(255, 255, 255, 0.8);
text-align: center;
line-height: 45px;
}
#banner .left:hover, #banner .right:hover {
background: rgba(0, 0, 0, 0.5);
cursor: pointer;
}
#banner .left {
left: 20px;
}
#banner .right {
right: 20px;
}
</style>
<script>
$(function() {
// 将#banner #bg中的第一个li复制一份, 放到#banner #bg的最后
$firstLiCopy = $("#banner #bg li:first").clone(true);
$("#banner #bg").append($firstLiCopy);
var imgWidth = 936;
var imgCount = $("#banner #bg li").length; // 此时, imgCount = 5, 但是实际上我们循环显示的只有4张
// 为了便于区分说明, 我们声明: 第1张图片为【真正的第1张图片】, 第5张图片为【真正的最后1张图片】
// 动态设置#banner #bg的宽度
$("#banner #bg").css("width", imgWidth * imgCount);
// 有多少张图片, 底部就有多个小圆圈
for (var i = 0; i < imgCount - 1; i++) { // i = 0, 1, 2, 3 < 4
$("#banner #aList").append($("<li></li>"));
}
// 动态纠正#banner #aList, 使其水平居中
$("#banner #aList").css("marginLeft", - $("#banner #aList").width() / 2);
// 底部小圆圈选中时的样式
var aSelectedCss = {
background: "rgba(255, 255, 255, 0.5)",
width: 30
};
// 底部小圆圈未选中时的样式
var aNoneCss = {
background: "rgba(0, 0, 0, 0.5)",
width: 20
};
// 一开始进来页面, 将底部的第一个小圆圈设置为选中的样式
$("#banner #aList li").eq(0).css(aSelectedCss);
var stayDuration = 2000;
var slideDuration = 500; // 一张图片滑动所需的时间
var curIndex = 0; // 当前的显示的图片的索引(从0开始)
// 根绝curIndex的变化, 动态设置底部那一排小圆圈的样式变化
// 在slide方法中被调用
function setA() {
// 类推一下。 当第1张图片滑动到第2张图片完成后, 此时curIndex = 1
// 当第4张图片滑动到第5张图片完成后, 换言之此时刚刚开始显示第5张(第1张的副本), 那么此时的curIndex为多少?
// 所以那么此时curIndex == imgCount - 1 == 4
if (curIndex == imgCount - 1) {
$("#banner #aList li").eq(0).css(aSelectedCss);
$("#banner #aList li").eq(0).siblings().css(aNoneCss);
return;
}
// 在这里是否需要考虑curIndex < 0的情况?
// 不需要!!!
$curA = $("#banner #aList li").eq(curIndex);
$curA.css(aSelectedCss);
$curA.siblings().css(aNoneCss);
}
// 滑动一张图片
function slide(isToLeft) { // ifToLeft = true : 表示从右向左滑动
if (isToLeft) {
curIndex++;
// 如果curIndex == 2, 说明第1张图片刚刚滑过去, 现在正在显示第2张图片
// 以此类推
// 如果curIndex == 5, 说明第4张图片刚刚滑过去, 现在正在显示第5张图片(第5张图片是第一张图片的副本)
if (curIndex >= imgCount) {
// 此时偷梁换柱, 一瞬间将位置瞬移到真正的第1张图片
curIndex = 1; // 第一张已经完成滑过动画了
$("#banner #bg").css("marginLeft", 0);
}
$("#banner #bg").stop().animate({
//marginLeft: "-=" + imgWidth // 不能使用这个, 否则当连续快速点击"<"会有bug
marginLeft: - curIndex * imgWidth
}, slideDuration, function() {
setA();
})
} else {
curIndex--;
// 如果curIndex == -1, 说明下面需要执行的动画就是: 【真正的第1张图片】滑动到【真正的最后1张图片】
// 不过在此之前, 先偷梁换柱, 将位置瞬移到第5张(第1张的副本)的位置
if (curIndex < 0) {
curIndex = imgCount - 2; // curIndex = 3
$("#banner #bg").css("marginLeft", - imgWidth * (imgCount-1));
}
$("#banner #bg").stop().animate({
//marginLeft: "+=" + imgWidth // 不能使用这个, 否则当连续快速点击">"会有bug
marginLeft: - curIndex * imgWidth
}, slideDuration, function() {
// if (curIndex == -1) 里面已经将curIndex重置为3, 所以在setA里面不要考虑curIndex < 0的情况
setA();
})
}
}
var timer = null;
// 开启自动滑动
function autoPlay() {
timer = setInterval(function() { // 这里给timer赋值了!!!
slide(true); // 从右向左滑动
}, stayDuration); // 先等待再执行
}
autoPlay(); // 一进页面, 轮播图自动滑动起来
$("#banner").hover(function() {
clearInterval(timer); // 鼠标悬停在轮播图(即#banner)时, 清除定时器timer
}, function() {
autoPlay(); // 鼠标移出时, 再开一个定时器
});
// 我们通过底部的小圆圈和左右的"<"和">"来切换图片的时候, 是否会影响和混乱轮播图的自动循环滑动?
// 不会!! 因为鼠标悬停在轮播图的时候, 我们已经将定时器timer的清除掉了
$("#banner #aList li").click(function() {
$(this).css(aSelectedCss);
$(this).siblings().css(aNoneCss);
curIndex = $(this).index();
$("#banner #bg").css("marginLeft", - imgWidth * curIndex);
});
$("#banner .left").click(function() {
slide(false);
});
$("#banner .right").click(function() {
slide(true);
});
});
</script>
</head>
<body>
<div id="banner">
<ul id="bg">
<li><img src="img/1.jpg"/></li>
<li><img src="img/2.jpg"/></li>
<li><img src="img/3.jpg"/></li>
<li><img src="img/4.jpg"/></li>
</ul>
<ul id="aList">
<!-- <li><a href="#"></a></li>
<li><a href="#"></a></li>
<li><a href="#"></a></li>
<li><a href="#"></a></li> -->
</ul>
<div class="left"><</div>
<div class="right">></div>
</div>
</body>
</html>