拥有以下效果
- 无缝切换
- 缓冲效果 (带有缓冲框架 在末尾)
- 点击左右切换
- 点击小按钮图片切换
- 自动播放(移入停止)
原理
先上结构代码再说原理
<body>
<div id="banner">
<ul class="pic">
<li><img src="img/maldives_4.jpg" alt="pic1"/></li>
<li><img src="img/maldives_1.jpg" alt="pic1"/></li>
<li><img src="img/maldives_2.jpg" alt="pic1"/></li>
<li><img src="img/maldives_3.jpg" alt="pic1"/></li>
<li><img src="img/maldives_4.jpg" alt="pic1"/></li>
<li><img src="img/maldives_1.jpg" alt="pic1"/></li>
</ul>
<ul class="btn"> //点击切换按钮(可在JS中改为移入)
<li class="active"></li>
<li></li>
<li></li>
<li></li>
</ul>
<div class="LRbtn"> //左右切换按钮
<span><</span>
<span class="right">></span>
</div>
</div>
</body>
可以看到 结构搭建里一共使用了6张图 而看到的效果却只使用了4
首先来说 :
如果不使用伪首页图片会出现什么状态?
你会发现当图片走到最后一张图过后 会反弹 回到第一张,这样的效果根本不符合所谓的无缝轮播,反弹出现的效果也不美观。
解决办法:
我们利用伪首页伪末尾图 也就是 在第一张的图片前放最后一张图 末尾放第一张,图片依然正常滚动 当图片走到 伪首页图时(从右往左走) 我们使他的父级数值调转到真正的的第一张图的位置, 所以当图片继续运动时,就会从第二张继续运动, 利用视觉差来巧妙的达到了 无缝轮播(无限轮播)
CSS样式
<style>
* {
margin: 0;
padding: 0;
}
li {
list-style: none;
}
img {
display: block;
}
#banner {
width: 800px;
height: 533px;
margin: 0 auto;
position: relative;
overflow: hidden;
}
#banner .pic {
position: absolute;
left: -800px; // 让图片呈现为真正的第一张
top: 0;
width: 4800px;
}
#banner .pic li {
float: left;
}
#banner .btn {
position: absolute;
left: 50%;
bottom: 50px;
transform: translateX(-50%);
}
#banner .btn li {
float: left;
width: 20px;
height: 20px;
background-color: #ccc;
margin: 0 5px;
border-radius: 50%;
font-size: 0;
}
#banner .btn .active {
background-color: #ff0;
}
#banner .LRbtn {
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 100%;
}
.LRbtn span {
float: left;
width: 30px;
height: 30px;
background-color: rgba(255, 255, 0, 0.5);
font-size: 20px;
line-height: 30px;
text-align: center;
color: #000;
cursor: pointer;
}
#banner .LRbtn .right {
float: right;
}
</style>
JS代码呈现:
<script>
window.onload = function () {
var obanner = document.getElementById('banner'); //获取最外层父级盒子
var opic = document.getElementsByClassName('pic')[0]; //获取ul
var opicli = opic.getElementsByTagName('li'); // 获取每一个li
var obtn = document.getElementsByClassName('LRbtn')[0]; // 左右两个切换按钮父级
var obtnclivc = obtn.getElementsByTagName('span'); // 左右连个切换按钮
var osbtn = document.getElementsByClassName('btn')[0]; // 获取小按钮的父级
var osbtnli = osbtn.getElementsByTagName('li'); //获取小按钮
var index = 1; //声明一个状态值
var timer = ''; //声明一个时间容器
timer = setInterval(move, 2000); //定时器开启
obanner.onmouseenter = function () {
clearInterval(timer); //移入最外层父级盒子 清除定时器
};
obanner.onmouseleave = function () {
timer = setInterval(move, 1000); //移除外层父级盒子 打开定时器
};
obtnclivc[0].onclick = function () { // 左点击切换
index -= 2;
// index-=2理由:封装的函数中已存在index++,如果继续使用index--就不起作用了 故此index-=2
move(); // 调用运动函数
console.log(index);
};
obtnclivc[1].onclick = function () { // 右点击切换
move(); // 调用运动函数
console.log(index);
};
for (i = 0; i < osbtnli.length; i++) {
osbtnli[i].index = i;
// 循环遍历所有的小按钮 同时保存当前按钮的下标值
osbtnli[i].onclick = function () {
for (var j = 0; j < osbtnli.length; j++) {
osbtnli[j].className = "";
//清除所有小按钮的类名
}
index = this.index+1;
// 统一index 值 并且使当前index值加1
this.className = 'active';
//给当前小按钮添加类名
bufmove(opic, {'left': -(index) * 800});
//JS封装好了的运动框架 后面会发 让ul的left值随 index值的变换而变换 800是一张图片的宽度
}
}
function move() { //运动函数
index++;
if (index < 0) {
opic.style.left = -3200 + 'px';
// opic的宽度跳到本体的最后张图;(利用视觉差)
index = 3;
//让index为3 做到伪无限图的效果
}
if (index > 5) {
opic.style.left = -800 + 'px';
// opic的宽度跳到本体的第一张图;
index = 2;
//让index为2 做到伪无限图的效果
}
for (i = 0; i < osbtnli.length; i++) {
osbtnli[i].className = '';
//清除所有小按钮的类名
}
if (index == 5) {
osbtnli[0].className = 'active';
//当index值为5时 也就是走到了 附第一张时
// 小按钮的类名又回到第一个也就是按钮下标为0的时候
} else if (index == 0) {
osbtnli[3].className = 'active';
//当index值为0时 也就是走到了 附最后一张时
// 小按钮的类名跳到最后一个就是按钮下标为3的时候
} else {
osbtnli[index - 1].className = 'active';
//index-1是因为初始状态值为0 我们要让小按钮的小标从0开始
}
bufmove(opic, {'left': -index * 800});
//JS封装好了的运动框架 让ul的left值随 index值的变换而变换 800是一张图片的宽度
}
}
</script>
缓冲框架
//用法bufmove(obox,{opacity:0.2,left:500});
// bufmove(obox2,{opacity:0.2,left:500,width:500},function(){
// bufmove(obox2,{opacity:1,left:1000});
// } );
function bufmove(obj,jsn,endFn){
// obj 对象 jsn (target 终止值jsn[attr] attr属性选择) endFn回调函数
clearInterval( obj.timer);
for(var attr in jsn){
if(attr== 'opacity'){
jsn[attr] *= 100;
}
}
obj.timer = setInterval(function(){
tag = true; // 假设全部到达终点
for(var attr in jsn){
if(attr =='opacity'){
var cur = parseFloat(getstyle(obj,attr)*100);
}else{
var cur = parseInt(getstyle(obj,attr)); //当前位置
}
var speed = ( jsn[attr] - cur)/10;
//速度:(目标值- 当前值)/缩放系数 (500 - 0 )/10 = 50
speed = speed>0 ? Math.ceil(speed): Math.floor(speed);
// 根据速度正负值来判断 取整的方向 如果速度大于0时 向右运动 故此 数值向右取整
if(cur != jsn[attr]){
// 当当前 并等于目标时 状态为假 重新执行 当所有值相同时才为真
tag =false;
}
if(attr =='opacity'){
obj.style[attr] = (cur+speed)/100;
}else{
obj.style[attr] = cur+speed + 'px';
// [] 括号里面能承载变量和字符串
}
}
if(tag){
// 状态为真后 关闭定时器
clearInterval( obj.timer);
// 关闭定时器之后 再调用函数
if(endFn){ // 回调
endFn();
}
}
},50)
}