js实现左右轮播图,实现效果有自动播放、点击分页器切换和点击左右按钮切换等。
原理
将一些图片在一行中平铺,然后计算偏移量再利用定时器实现定时轮播。
实现效果
-
多张图片自动轮换展示,对应分页器小圆点高亮显示
-
图片无缝切换(图片列表中第一张和最后一张图片一致)
-
鼠标滑入/滑出停止/开启图片轮换展示
-
点击前进/后退按钮查看当前图片前一张/后一张图片
-
点击分页器小圆点切换对应图片
实现思路
-
获取操作对象
-
请求数据
-
渲染数据
-
封装函数autoMove,将其传入定时器,实现图片自动轮换展示
-
封装函数changeFocus,实现图片对应分页器小圆点高亮显示
-
绑定鼠标滑入/滑出事件,滑入(滑出)清除(开启)定时器
-
给左右按钮绑定点击事件
index.js
//获取外层的窗口
let outer = document.getElementById('outer');
//获取图片的容器
let wrapper = document.getElementById('wrapper');
//获取焦点的容器
let list = document.getElementById('list');
let data = null; //用来接收请求的数据
let timer = null;//用来接收定时器的返回值
//1.数据请求
function getData(url) {
let xhr = new XMLHttpRequest;
xhr.open('get', url, false);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && /^2\d{2}/.test(xhr.status)) {
data = JSON.parse(xhr.responseText);
}
}
xhr.send();
// console.log(data);
}
getData('banner.json');
//2.数据渲染
function renderHtml() {
let wrapperItems = '';
let listItems = '';
data.forEach((item, index) => {
wrapperItems += `<li><img src="${item.img}" alt=""></li>`;
listItems += `<li></li>`;
});
//再复制第一张图片放到末尾(让第一张和最后一张一样)
wrapperItems += `<li><img src="${data[0].img}" alt=""></li>`;
// console.log(wrapperItems);
//把动态生成的图片插入到页面
wrapper.innerHTML = wrapperItems;
//把动态生成的焦点插入到页面
list.innerHTML = listItems;
}
renderHtml();
//存储当前展示图片的索引
let step = 0;
/*autoMove
图片索引自增(切换下一张图片)
如果当前索引是最后一张图片,将图片列表ul(绝对定位)的left值设置为0,将索引值设为1
一定时间内修改图片列表ul(绝对定位)的left值为 负的每张图片长度*索引(动画)
*/
function autoMove(index) {
step++;
//如果当前的函数执行的时候index没有值,那就什么都不做,如果index有值,那就把index的值赋值给step即可
typeof index === 'undefined' ? null : step = index;
//如果当前的step大于等于5,说明当前已经运动到最后一张图片了,这时候需要马上把wrapper的left值改为0(因为第一张和最后一张一样,所以看不见这个变化)
//这时候再把step改为1,正常展示第二张
if (step >= data.length+1) {
wrapper.style.left = 0;
step = 1;
}
changeFocus();
utils.animate(wrapper, { left: -step * 800 }, 500);
}
timer = setInterval(autoMove, 2000);
//用户鼠标滑上outer轮播停止,鼠标离开轮播继续
outer.onmouseover = function () {
clearInterval(timer);
}
outer.onmouseout = function () {
timer = setInterval(autoMove, 2000);
}
let tips = document.querySelectorAll('#list li');//querySelectorAll获取的元素没有映射
//实现焦点跟随
/*changeFocus
如果当前图片索引与分页器索引一致则给当前分页器添加类名active,其他分页器删除类名active(循环)
如果图片索引是最后一张图片,给第一个分页器添加类名active
*/
function changeFocus() {
//切换焦点的显示
//循环所有的焦点,判断一下当前的step和哪个焦点的索引相等,和谁相等就给谁加上active类名,其余的清除active类名
for (let i = 0; i < tips.length; i++) {
//tips[i] //每一个焦点 i就是每一个焦点的索引
if (step === i) {
tips[i].classList.add('active');
} else {
tips[i].classList.remove('active');
}
}
//如果当前的step是4,说明当前页面显示的是最后一张图片,他和第一张图片共用一个焦点,这时候让第一个焦点高亮就可以了
if (step === 4) {
tips[0].classList.add('active');
}
}
//页面初始化的时候执行一次,为了让第一张图片的焦点高亮
changeFocus();
//点击焦点,实现切换对应的图片
function bindClick() {
for (let i = 0; i < tips.length; i++) {
tips[i].onclick = function () {
/* //方式一
//因为autoMove内部有step++,所以这这里要减一,这样就会跟autoMove内部的step++相互抵消
step=i-1;
autoMove(); */
//方式二
autoMove(i);
}
}
}
bindClick();
//点击小耳朵实现图片切换
right.onclick = function () {
autoMove();
}
//左按钮点击事件
left.onclick = function () {
step -= 2;//图片索引减2(autoMove中索引 会自增)
if (step == -2) {
//如果索引等于-2,说明现在要显示倒数第二张图片,需要将left设置为负的总图片长度(负的单张图片长度*data.length)
wrapper.style.left = -data.length * 800 + 'px';
step = data.length - 2;//索引设置为data.length-2
}
autoMove();
}
utils.js
let utils = (function(){
function linear(t,b,c,d){
return c/d*t+b;
}
// move
function animate(curEle,target,duration,callBack){
let begin = {};
let change = {};
for(var key in target){
begin[key] = parseFloat(getComputedStyle(curEle)[key]);
change[key] = target[key] - begin[key];
}
let interval = 0;
let timer = setInterval(function(){
interval+=20;
for(var key in target){
let cur = linear(interval,begin[key],change[key],duration);
// console.log(interval,begin[key],change[key],duration)
curEle.style[key] = cur+'px';
}
if(interval>=duration){
clearInterval(timer);
typeof callBack === 'function'? callBack():null
}
},20)
};
function debounce(fn,wait){
let timer;
return function(){
clearInterval(timer);
timer = setTimeout(()=>{
fn.call(this);
},wait)
}
}
return {animate,debounce}
})()
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" href="index.css">
</head>
<body>
<div id="outer">
<!-- 图片 -->
<ul id="wrapper">
<li><img src="img/banner1.jpg" alt=""></li>
<!-- <li><img src="img/banner2.jpg" alt=""></li>
<li><img src="img/banner3.jpg" alt=""></li> -->
</ul>
<!-- 焦点 -->
<ul id="list">
<li class="active"></li>
<li></li>
<li></li>
<li></li>
</ul>
<!-- -->
<a href="javascript:;" id="left"> < </a>
<a href="javascript:;" id="right"> > </a>
</div>
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-1.11.3.min.js"></script>
<script src="utils.js"></script>
<script src="index.js"></script>
</body>
</html>
index.css
*{
margin: 0;
padding: 0;
}
#outer{
width: 800px;
height: 300px;
margin: 100px auto;
border: 1px solid red;
overflow: hidden;
position: relative;
cursor: pointer;
}
#wrapper{
display: flex;
/* width: 2400px; */
height: 300px;
background: orangered;
position: absolute;
left: 0;
list-style: none;
}
#wrapper li{
width: 800px;
height: 300px;
}
#wrapper li img{
display: block;
width: 100%;
height: 100%;
}
/* -------------------------- */
#list{
/* width: 250px; */
height: 30px;
/* background: palevioletred; */
position: absolute;
left: 50%;
list-style: none;
display: flex;
/* justify-content: space-around; */
align-items: center;
transform: translate(-50%,0);
bottom: 10px;
}
#list li{
width: 25px;
height: 25px;
margin: 0 5px;
border-radius: 50%;
background: rgba(0, 0, 0, .5);
}
#list li.active{
background: orangered;
}
/* ------------------------------ */
#outer a{
width: 30px;
height: 50px;
text-align: center;
line-height: 50px;
background: rgba(0,0,0,.5);
position: absolute;
top: 50%;
text-decoration: none;
color: #fff;
}
#left{
left: 0;
}
#right{
right: 0;
}
banner.json
[
{
"id": 1,
"img": "img/banner1.jpg",
"desc": "广阔的就业推荐机会",
"link": "http://www.zhufengpeixun.cn/"
},
{
"id": 2,
"img": "img/banner2.jpg",
"desc": "梦想起飞从选择珠峰培训开始",
"link": "http://www.zhufengpeixun.cn/"
},
{
"id": 3,
"img": "img/banner3.jpg",
"desc": "把握未来,掌握先机",
"link": "http://www.zhufengpeixun.cn/"
},
{
"id": 4,
"img": "img/banner4.jpg",
"desc": "先学习,后交费,学不好,不收费",
"link": "http://www.zhufengpeixun.cn/"
}
]