一、原理
每次只显示一张图片,其余隐藏。通过计算偏移量利用定时器实现自动播放,或通过手动点击事件切换图片。
二、实现:
- 给最外面的div容器固定的宽高,使内部的ul和li与div宽高相同(height:100%;width:100%),设置overflow:hidden,只显示一张图片
- 为了实现无缝切换效果,利用两张辅助图填补最后一张图切换到第一张图时的空白。即复制最后一张图片放置在第一张图片前,同时复制第一张图片放置在最后一张图片的后面。
- 让内部的ul强制不换行(white-space: nowrap; ),即所有的li排成一行,并且让ul往前平移自身的宽度(transform: translateX(-100%);),即默认显示实际图片的第一张图。
三、代码展示
- banner.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="css/reset.css"/>
<link rel="stylesheet" type="text/css" href="css/public.css"/>
<link rel="stylesheet" type="text/css" href="css/banner.css"/>
<title></title>
</head>
<body>
<div class="banner">
<!-- 真正滑动的是ul -->
<ul class="banner-slider">
<!-- 在第一张之前多放一个最后一张,在最后一张多放一张第一张,目的是实现无缝轮播 -->
<li><a href="#"><img src="images/banner-004.jpg" ></a></li>
<li><a href="#"><img src="images/banner-001.jpg" ></a></li>
<li><a href="#"><img src="images/banner-002.jpg" ></a></li>
<li><a href="#"><img src="images/banner-003.jpg" ></a></li>
<li><a href="#"><img src="images/banner-004.jpg" ></a></li>
<li><a href="#"><img src="images/banner-001.jpg" ></a></li>
</ul>
<!-- 指示器 -->
<ul class="banner-indicator">
<li class="active"></li>
<li></li>
<li></li>
<li></li>
</ul>
<!-- 两边的耳朵,左右箭头 -->
<span class="banner-prev"></span>
<span class="banner-next"></span>
</div>
<script src="js/banner.js" type="text/javascript" charset="utf-8"></script>
</body>
</html>
- banner.css
/* 思路:
使ul和li设置的与div宽高相同,最外面的大div固定,里面的ul带着li跑。
*/
.banner {
width: 1000px;
height: 400px;
margin: 100px auto;
position: relative;
overflow: hidden;
}
ul.banner-slider {
/* transition: all 1s ease-out; 这里的过渡切换动画时间由js控制 */
transition-property: all;
transition-timing-function: ease-out;
width: 100%;
height: 100%;
font-size: 0;
white-space: nowrap; /* 强制不换行,使得所有的li排在一行 */
transform: translateX(-100%); /* 由于第一张前多加了一张,所以需要ul往前平移一张图片的距离,默认显示实际的第一张 */
}
ul.banner-slider>li {
display: inline-block;
width: 100%;
height: 100%;
}
ul.banner-slider>li>a {
display: block;
height: 100%;
}
ul.banner-slider>li>a>img {
width: 100%;
height: 100%;
}
/* banner指示器 */
ul.banner-indicator {
position: absolute;
bottom: 25px;
/* 先向左平移50%,再平移自身的一半,即实现居中显示 */
left: 50%;
transform: translateX(-50%);
}
ul.banner-indicator>li {
float: left;
width: 50px;
height: 20px;
background-color: rgba(0,0,0,0.5);
border-radius: 4px;
overflow: hidden; /* 由于四个角显示了圆角,所以需要将多余的部分隐藏掉 */
margin: 0 10px;
}
/* 实现指示器切换的过渡动画 */
ul.banner-indicator>li::before {
content: '';
float: right;
width: 0;
height: 100%;
background-color: coral;
transition: all 1s ease-out; /* 与上面的动画过渡时间相同 */
}
ul.banner-indicator>li.active::before {
width: 100%;
float: left;
}
/* 左右两个耳朵 */
span.banner-prev,span.banner-next {
width: 50px;
height: 100px;
position: absolute;
top: 50%;
transform: translateY(-50%);
background-color: rgba(0,0,0,0.3);
cursor: pointer;
}
span.banner-prev:hover,span.banner-next:hover {
background-color: rgba(0,0,0,0.6);
}
span.banner-prev {
left: 5%;
}
span.banner-next {
right: 5%;
}
- banner.js
//全局变量
var index = 0; //记录当前哪一张是激活的,默认实际图片的第一张
var interval = 5000; //轮播图轮播的间隔时间(观看时间5s换下一张)
var timer = null; //保存计时器对象
var count = 4; //总共实际要轮播的图片数量
var lock = false; //标识是否在执行动画,解决频繁点击下一张出现的bug,默认不执行动画,没有锁。
//自动播放、点击轮播图指示器、点击上一张下一张按钮的时候 三种情况都可调用该切换函数
//切换函数slide——核心函数
//将下一张编号的更新操作全部都放在了slide函数中,其它函数则不用考虑编号更改问题。
function slide(nextIndex) {
//nextIndex(下一张编号):可取到 -1,0,1,2,3,4
//index:0 1 2 3
if(lock) return; //如果当前正在执行轮播动画,已经加锁,则直接返回
lock = true; //没加锁,接着开始执行轮播动画,需要加锁!
//图片切换
var slider = document.querySelector('ul.banner-slider');
slider.style.transitionDuration = '1s';
slider.style.marginLeft = -1 * nextIndex + '00%';
//指示器切换
var indicators = document.querySelectorAll('ul.banner-indicator>li');
indicators[index].className = ''; //让当前激活的indicator不激活
//更新index(三种情况通用)
if(nextIndex === count) index = 0; //若下一张到了4,则立即回到第一张0
else if(nextIndex === -1) index = count - 1;
else index = nextIndex;
indicators[index].className = 'active'; //让更新后的index激活
//重置实现无缝效果
setTimeout(function() {
slider.style.transitionDuration = '0s'; //不设置动画,秒回到第一张,回到第一张后再执行上面的动画
if(nextIndex === count) slider.style.marginLeft = '0%';
if(nextIndex === -1) slider.style.marginLeft = -1 * (count - 1) +'00%';
lock = false; //动画结束后,开锁!
},1020);
}
//自动播放
function play() {
//每隔指定时间滑动(切换)一次
timer = setInterval(function() {
slide(index + 1);
},interval);
}
//鼠标滑过banner区域,暂停自动播放
document.querySelector('.banner').onmouseover = function() { clearInterval(timer);};
//鼠标滑出banner区域,恢复自动播放
document.querySelector('.banner').onmouseout = function() { play(); };
// 点击指示器切换轮播图
var indicators = document.querySelectorAll('ul.banner-indicator>li');
for(var i = 0; i < indicators.length; i++) {
//将每一个li绑定一个属性num,用来藏每一个li的序号,则滑动时用这个序号标识滑到第几张即可
indicators[i].num = i;
indicators[i].onclick = function() {
if(this.className === 'active') return;
slide(this.num);
};
}
//上一张 点击事件绑定(左箭头)
document.querySelector('span.banner-prev').onclick = function() {
slide(index - 1);
};
//下一张 点击事件绑定(右箭头)
document.querySelector('span.banner-next').onclick = function() {
slide(index + 1);
};
//调用play开始首次自动播放
play();
四、总结
(1)容器的css布局。
(2)核心是切换函数,将编号的更新集中处理。每一次轮播通过偏移量(margin-left)实现。
(3)自动轮播,通过setInterval()方法实现定时器,执行切换函数
(4)鼠标控制轮播的暂停和继续。通过onmouseover为暂停(利用clearInterval() 清除计时器),onmouseout为继续。