轮播图的原理:
一系列的大小相等的图片平铺,利用CSS布局只显示一张图片,其余隐藏。通过计算偏移量利用定时器实现自动播放,或通过手动点击事件切换图片。
HTML布局
父容器box存放所有内容,子容器screen存放图片,current存放按钮序号.
left/right做移入出现箭头,点击左右滑动图片效果
<div class="all" id='box'>
<div class="screen">
<ul>
<li><img src="image/timg.jpg" width="500" height="200" /></li>
<li><img src="image/11.jpg" width="500" height="200" /></li>
<li><img src="image/timg2.jpg" width="500" height="200" /></li>
<li><img src="image/timg3.jpg" width="500" height="200" /></li>
<li><img src="image/timg4.jpg" width="500" height="200" /></li>
</ul>
<ol>
<li class="current">1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ol>
</div>
<div id="arr"><span id="left"><</span><span id="right">></span></div>
</div>
CSS布局
screen里设置overflow: hidden;可以只显示视口大小的图片,其余隐藏.
这里注释掉是为了方便观察效果,
<style type="text/css">
* {
padding: 0;
margin: 0;
list-style: none;
border: 0;
}
.all {
width: 500px;
height: 200px;
padding: 7px;
border: 1px solid #ccc;
margin: 100px auto;
position: relative;
}
.screen {
width: 500px;
height: 200px;
/* overflow: hidden; */
position: relative;
}
.screen li {
width: 500px;
height: 200px;
overflow: hidden;
float: left;
}
.screen ul {
position: absolute;
left: 0;
top: 0px;
width: 3500px;//五张图片加两张复制的宽度
}
.all ol {
position: absolute;
right: 10px;
bottom: 10px;
line-height: 20px;
text-align: center;
}
.all ol li {
float: left;
width: 20px;
height: 20px;
background: #fff;
border: 1px solid #ccc;
margin-left: 10px;
cursor: pointer;
}
.all ol li.current {
background: yellow;
}
#arr {
display: none;
}
#arr span {
width: 40px;
height: 40px;
position: absolute;
left: 5px;
top: 50%;
margin-top: -20px;
background: #000;
cursor: pointer;
line-height: 40px;
text-align: center;
font-weight: bold;
font-family: '黑体';
font-size: 30px;
color: #fff;
opacity: 0.3;
border: 1px solid #fff;
}
#arr #right {
right: 5px;
left: auto;
}
</style>
js部分
1:鼠标进去的时候,显示左右两个箭头,鼠标移出,隐藏箭头
获取相关要操作的数据
let box = document.getElementById('box');
let arr = document.getElementById('arr');
let left = document.getElementById('left');
let right = document.getElementById('right');
let screen = box.querySelector('.screen');
let ul = screen.querySelector('ul');
let ol = screen.querySelector('ol');
let uLis = ul.children;
let oLis = querySelectorAll('li');
移入事件:box事件onmouseover:显示div#arr
移出事件:box事件onmouseout:隐藏div#arr
box.onmouseover = function () {
arr.style.display = 'block';
};
box.onmouseout = function () {
arr.style.display = '';
};
2:点击左右两边的箭头,向左,图片看上一张;向右,图片看下一张
优化,无缝滚动。
当从最后一张图切换回第一张图时,会有很大空白过渡,利用两张辅助图来填补这个空白。
这里补充下无缝滚动,直接看代码,复制最后一张图片放置第一张图片前,同时复制第一张图片放置最后一张图片的后面。
//拿到图片:第一个li和最后一个li(深克隆)
let first = uLis[0].cloneNode(true);
let last = uLis[uLis.length - 1].cloneNode(true);
//将第一张放到最后,最后一张放到最前
ul.insertBefore(last, uLis[0]);
ul.appendChild(first);
用户应该看到的是第一张图片:让整个ul向左移动500:screen.offsetWidth == 500
box.style.left = -screen.offsetWidth + 'px';
3. 定义一个变量( 全局): 用来记录当前图片的位置:
let index = 1;//1 此时代表是真正的第1张(也就是现在的第2张)
封装一个缓速动画做效果,以后可以随时调用.
创建一个后缀为.js的文档.
/**
* 缓速动画(向右移动)
* @param {element} ele ,要移动的元素
* @param {number} target,要移动的目标位置
*/
function animateSlow(ele, target) {
// 清理定时器:元素自己的定时器,自己保存
// ele.timeId 访问ele对象的timeId属性:没有得到的结果undefined
clearInterval(ele.timeId); // 有就清除,没有就什么都没做
// ele的移动:将当前元素自己的定时器存到自己的对象属性中
ele.timeId = setInterval(function () {
// 拿到ele的边距
let left = ele.offsetLeft;
// 计算步长
// 如果是向右移动:最终是1px移动:Math.ceil(小数) 得到1
// 如果是向左移动:最终是-1px移动:Math.ceil(-小数) 得到0
// let step = Math.ceil((target - left) * 0.1);
// 让step根据目标结果(可正可负)
let step = (target - left) * 0.1;
// 根据step的正负关系:求最小的1px
// step > 0 :target(目标)比left(当前位置)大,向右移动:+1
// step < 0 :target(目标)比left(当前位置)小,向左移动:-1
step = step > 0 ? Math.ceil(step) : Math.floor(step);
// 计算下一个位置
let next = left + step;
// console.log(left, step);
// 判定位置
if (next == target) {
// 下一步要到target:直接设定target
ele.style.left = target + 'px';
// 终止定时器:定时器存储在自己ele的属性中
clearInterval(ele.timeId);
// 结束当前函数
return;
}
// 正常移动
ele.style.left = next + 'px';
}, 20);
};
引入动画js文档
4. 点击左键事件操作:移动ul,移动是screen屏幕对应的宽度(li)
// left.onclick = funciton(){}; // 匿名回调
left.onclick = leftClick;
function leftClick() {
// 看前一张:下标-1即可
index--;
// 做动画:index变成了0,让ul移动:移动 -index * screen.offsetWidth
animateSlow(ul, -index * screen.offsetWidth);
}
一直点击运行后会发现出现空白,只能通过点击右键才能回往回走
function leftClick() {
if (index == 0) {
//index--就表示前面一张图片,如果index已经等于0:说明当前的图片本质是看的最后一张(效果是第一张):为了保证动画效果
// 让index瞬间变成倒数第二张:最后加了个第一张
index = uLis.length - 2;
// 让ul瞬间移动到倒数第二张
ul.style.left = -index * screen.offsetWidth + 'px';
}
// 看前一张:下标-1即可
index--;
// 做动画:index变成了0,让ul移动:移动 -index * screen.offsetWidth
animateSlow(ul, -index * screen.offsetWidth);
}
右边同理,让ul向左移动
right.onclick = rightClick;
function rightClick() {
// 如果index已经是最后一张:本质代表的是有效第一张:瞬移到一张:index应该重置为1
if (index == uLis.length - 1) {
index = 1; // 回到第一张(此时看的是最后一张)
// 瞬移到第一张
ul.style.left = -screen.offsetWidth + 'px';
}
index++;
// 3. 动画效果
animateSlow(ul, -index * screen.offsetWidth);
把css样式里面的隐藏注释解开,大致的样子就做出来了,可以左右点击试下效果
接下来做点击左右按钮根据图片转换数字序号
function leftClick() {
if (index == 0) {
// 要考虑index = 0,本身当前看到的是第5张,下一次要看第4张
oLis[index == 0 ? oLis.length - 1 : index - 1].classList.remove('current');//去除赋值给li下标的类名
index = uLis.length - 2;
ul.style.left = -index * screen.offsetWidth + 'px';
}
index--;
animateSlow(ul, -index * screen.offsetWidth);
oLis[index == 0 ? oLis.length - 1 : index - 1].classList.add('current');//赋值给已经自减li下标的类名
}
右边
right.onclick = rightClick;
function rightClick() {
oLis[index == uLis.length - 1 ? 0 : index - 1].classList.remove('current');
// 如果index已经是最后一张:本质代表的是有效第一张:瞬移到一张:index应该重置为1
if (index == uLis.length - 1) {
index = 1;
ul.style.left = -screen.offsetWidth + 'px';
}
index++;
animateSlow(ul, -index * screen.offsetWidth);
oLis[index == uLis.length - 1 ? 0 : index - 1].classList.add('current');
点击页面数字可以直接跳到对应的图片上
// 1. oLis里面的li的下标与 index之间的关系: oLis的下标 + 1 = index
oLis.forEach(function (item, key) {
//item代表元素,key代表下标
item.onclick = function () {
let oldOlisKey = index - 1;
if (index == 0) oldOlisKey = oLis.length - 1;
if (index == 6) oldOlisKey = 0;
//求出原来的页面的下标: 去除原来页码的样式
oLis[oldOlisKey].classList.remove('current');
//计算index当前的值: index = 当前页码下标 + 1
index = key + 1;
console.log(index)
//利用index动画效果实现
animateSlow(ul, -index * screen.offsetWidth);
//将当前页面对应的样式: 高亮显示
item.classList.animateSlow('current');
轮播图就是会自己动,少不了定时器,定时器有setTimeout(回调函数,时间间隔),setInterval(回调函数,时间间隔)两种,前者执行一次,后者无限.
最后实现定时器触发自动向右轮播:let 变量=setInterval(回调函数,毫秒);
写在页面最开始获取元素后面加上即可.
let timeId = setInterval(rightClick, 3000);
加强版: 鼠标移入box的时候:清除自动轮播定时器.
添加到页面最开始box移入函数里面
clearInterval(timeId);
鼠标移出box的时候:又继续轮播
添加到页面最开始box移出函数里面
timeId = setInterval(rightClick, 3000);
总结:要清楚理解到下标/图片播放模式,代码量不算多,基本做完左边右边复制粘贴修改一下就可以了.
顺带还封装了个动画,比较占代码,大家可以根据自身需求修改.有不明白的或建议可以留言.