效果图
首先我们来理一下思路
-
搭建结构
注意点:
我们需要一个container轮播图容器,溢出隐藏
我们需要一个wrapper容器用于存放所有的图片,wrapper相对于container定位,后期改变wrapper的left值实现轮播图的切换 -
写样式…
-
写js
- 获取所有需要操作的元素
- 获取数据(基于AJAX异步获取数据,当然没有服务器提供数据,只能自己写一点)
- 实现数据绑定HTML页面(基于Promise管理异步操作)
注意绑定的时候图片要多绑定一个,便于后面实现无缝轮播- (每隔interval秒,实现单张轮播图的自动运动和切换)
- 实现轮播图的自动运动和切换
- 设置轮播图运动的基础参数(全局变量)stepIndex,autoTimer,interval
- 开启定时器驱动自动轮播(实现每隔interval秒轮播图的自动运动和切换)
- stepIndex++(图片要切换了,当前图片索引改变)
- 当索引大于原来的长度,让其立即运动到第一张,再让其运动第二张(最后一张图片和第一张图片一摸一样,立即运动表示直接设置它的left属性,让它在运动最后一张图片的时候切换到第一张图片,人眼是看不出来的跳转的,这样可以实现无缝衔接)
- 设置动画(让图片在1秒内完成切换)
- 切换焦点- 实现鼠标进入和离开自动轮播的停止和开启,和按钮的隐藏和显示
- 实现点击焦点时图片的切换
- 实现点击按钮时图片的切换
然后直接上代码!!!
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>轮播图</title>
<link rel="stylesheet/less" href="css/banner.less">
<script src="js/less.min.js"></script>
</head>
<body>
<section class="container" id="container">
<div class="wrapper">
<!-- <div><img src="img/1.png" alt=""></div>
<div><img src="img/2.png" alt=""></div>
<div><img src="img/3.png" alt=""></div>
<div><img src="img/4.png" alt=""></div> -->
</div>
<ul class="focus">
<!-- <li class="active"></li>
<li></li>
<li></li>
<li></li> -->
</ul>
<a href="javascropt:;" class="arrow arrowLeft"></a>
<a href="javascropt:;" class="arrow arrowRight"></a>
</section>
<script src="js/utils.js"></script>
<script src="js/animate.js"></script>
<script src="js/banner.js"></script>
</body>
</html>
css
@import "baseCss";
.container{
position: relative;
margin: 20px auto;
width: 1000px;
height: 300px;
overflow: hidden;
.wrapper{
position: absolute;
left: 0;
top: 0;
width: 4000px;
height: 100%;
div{
float: left;
width: 1000px;
height: 100%;
img{
width: 100%;
height: 100%;
}
}
}
.focus{
position: absolute;
left: 50%;
bottom: 10px;
transform: translateX(-50%);
height: 12px;
border-radius: 6px;
background: rgba(0, 0, 0, .5);
li{
float: left;
margin: 3px;
width: 6px;
height: 6px;
background: #fff;
border-radius: 50%;
&.active{
background: lightseagreen;
}
}
}
.arrow{
position: absolute;
display: none;
width: 41px;
height: 69px;
&.arrowLeft{
left: 0;
top: 50%;
transform: translateY(-50%);
background: url(../img/icon-slides.png) no-repeat -84px 0;
&:hover{
background: url(../img/icon-slides.png) no-repeat 0 0;
}
}
&.arrowRight{
right: 0;
top: 50%;
transform: translateY(-50%);
background: url(../img/icon-slides.png) no-repeat -126px 0;
&:hover{
background: url(../img/icon-slides.png) no-repeat -42px 0;
}
}
}
}
js
let bannerRender = (function() {
//1. 获取操作的的元素
let container = document.querySelector('#container'),
wrapper = container.querySelector('.wrapper'),
focus = container.querySelector('.focus'),
arrowLeft = container.querySelector('.arrowLeft'),
arrowRight = container.querySelector('.arrowRight'),
slideList = null,
focusList = null;
//轮播图运动的基础参数
let stepIndex = 0, //记录当前展示快的索引
autoTimer = null, //自动轮播的定时器
interval = 3000; //间隔多长时间自动切换
//2. 获取数据
let queryData = function() {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open('get', 'json/banner.json', true); //异步获取数据
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
let data = JSON.parse(xhr.responseText);
resolve(data);
}
};
xhr.send(null);
});
};
//3. 实现数据绑定(获取数据成功之后执行数据绑定方法)
let bindHTML = function(res) {
let strSlide = ``,
strFocus = ``;
res.forEach((item, index) => {
let {
id,
img = 'img/1.png',
desc = 'xiaomi',
link
} = item;
strSlide += `<div><img src="${img}" alt="${desc}"></div>`;
//ES6模板字符串${}存放的是JS表达式,但是表达式要有返回值,因为我们要把返回值拼接到模板字符串中
strFocus += `<li class="${index === 0?'active':''}"></li>`
});
//克隆一份到末尾
strSlide += `<div><img src="${res[0].img}" alt="${res[0].desc}"></div>`;
wrapper.innerHTML += strSlide;
focus.innerHTML += strFocus;
slideList = wrapper.querySelectorAll('.wrapper > div');
focusList = focus.querySelectorAll('.focus > li');
//根据slide的个数动态计算wrapper的宽度
utils.setCss(wrapper, 'width', slideList.length * 1000);
};
//改变焦点
let changeFocus = function() {
let tempIndex = stepIndex; //创建临时索引
tempIndex === slideList.length - 1 ? tempIndex = 0 : null;
[].forEach.call(focusList, (item, index) => {
item.className = index === tempIndex ? 'active' : '';
});
};
//4. 实现轮播图的运动和切换
//轮播图无缝衔接原理:
//- 克隆第一张到末尾(在数据绑定的时候克隆)
//- 正常累加运动,当运动到末尾(此时的末尾是克隆的哪一张),再过3秒切换的时候,后面就没有图片了,此时我们让其立即切换到真实第一张的位置
// (立即切换,没有动画,left=0,刚才展示的最后一张和真实的第一张长的一样,给用户感觉没有切换),紧接着运动到第二张即可
let autoMove = function() {
stepIndex++;
//如果索引大于原来的长度,让其瞬间运动到第一张,再让其运动到第二张
if (stepIndex > (slideList.length - 1)) {
utils.setCss(wrapper, 'left', 0);
stepIndex = 1; //不是等于0,而是等于1,这样可以切换到第二张
}
//基于自己封装的animate实现动画
animate(wrapper, {
left: -stepIndex * 1000
}, 1000);
//每一次运动完成,需要让焦点跟着切换
changeFocus();
};
//5. 实现鼠标进入和离开控制自动轮播的停止和开启
let handleContainer = function() {
container.onmouseenter = function() {
clearInterval(autoTimer);
arrowLeft.style.display = arrowRight.style.display = 'block';
};
container.onmouseleave = function() {
autoTimer = setInterval(autoMove, interval);
arrowLeft.style.display = arrowRight.style.display = 'none';
};
};
//6. 实现点击焦点图片切换
let handleFocus = function() {
[].forEach.call(focusList, (item, index) => {
item.onclick = function() {
stepIndex = index;
animate(wrapper, {
left: -stepIndex * 1000
}, 1000);
changeFocus();
};
});
};
//7. 实现点击按钮图片
let handleArrow = function() {
arrowRight.onclick = autoMove;
arrowLeft.onclick = function() {
stepIndex--;
//如果索引小于零,则是第一张,不能再向右运动了,此时因当瞬间运动到最后一张(和第一张一模一样),再让其运动到倒数第二张
if (stepIndex < 0) {
utils.setCss(wrapper, 'left', -(slideList.length - 1) * 1000);
stepIndex = slideList.length - 2;
}
animate(wrapper, {
left: -stepIndex * 1000
}, 1000);
changeFocus();
};
}
return {
init: function() {
let promise = queryData();
promise.then(res => {
bindHTML(res);
}).then(() => {
//开启定时器驱动的自动轮播
autoTimer = setInterval(autoMove, interval);
}).then(() => {
//左右按钮或者焦点切换
handleContainer();
handleFocus();
handleArrow();
});
}
};
})();
bannerRender.init();