无缝轮播在显示开发中还是比较常见的,基本每个网站都或多或少的用到无缝轮播。
这里写一下之前写的无缝轮播是如何实现的。
这个轮播的实现利用了自己写的匀速运动框架,请先看另一篇博客中对匀速运动框架的介绍
需求
- 不做任何操作时候,图片自动向左滑动
- 可以进行上一张和下一张操作
- 鼠标悬停在图片上时候停止播放
- 鼠标离开时候从当前的图片继续往后播放
- 点击圆点选项时候能够从当前滑动到对应图片
- 实现无缝:播放到最后一张时候第一张从右面滑入,当前是第一张的时候,点击上一张,最后一张图片从左面向右滑的效果
思路
- 使用两个ul,分别来装图片和标志当前顺序的选项圆点,两个按钮来实现上一张和下一张的点击
- 通过改变ul的left值来达到在可见位置的切换图片效果
- 图片滑动:利用自己提前写好的自定义运动框架,实现图片的滑动效果
- 自动播放:把动画触发的写进下一张和上一张的点击事件中,利用setInterval来不断调用下一张的点击事件实现自动播放
- 实现无缝:通过在最后一张图片的后面追加第一张图片,作为第一张图片的复制品,
- 下一张或者正常播放的时候,图片滑到最后一张,继续下一张滑动到第一张的复制品上,这个动画完成后直接改变ul的left值为0显示第一张,继续从第一张向第二张滑动
- 上一张时候,先把ul的left值切换到第一张图片替代品上,然后执行从第一张替代品向最后一张图的动画效果
- 鼠标移入停止动画,清除当前的setInterval
- 鼠标移出时候继续播放,重新设置setInterval
- 检测两次点击时间,避免动画没有完成就需要进行下一次动画
效果图
不会截取动画,就先用图片代替了
代码
HTML结构
<div class="wrap">
<!--图片-->
<ul class="imgs">
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
<!--圆点-->
<div class="dots">
<ul>
<li class="checked"></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</div>
<!--上一张-->
<div class="turn previous"> <</div>
<!--下一张-->
<div class="turn next"> ></div>
</div>
引用匀速运动框架
<script src="uniformMotionFrame.js"></script>
轮播功能实现部分
//轮播实现部分
let oWarp = document.getElementsByClassName('wrap')[0],
aImgs = document.getElementsByTagName('ul')[0],
aDots = document.querySelectorAll('.dots ul li'),
oNext = document.getElementsByClassName('next')[0],
oPrevious = document.getElementsByClassName('previous')[0],
timer,
index = 0,
lastTime = new Date();
const len = aDots.length, imgWidth = 1000;
//上一个按钮点击事件
oPrevious.onclick = () => {
if (new Date() - lastTime < 1000) {
return; //两次点击小于1s,不做任何操作
}
lastTime = new Date();
index--;
if (index < 0) {
index = len - 1
aImgs.style.left = 1 - len * imgWidth + 'px'; //回到最后一张替身上
}
unifromMotion(aImgs, { 'left': imgWidth }, 500); //从替身 往前走
changeImg(index);
}
//下一个按钮点击事件
oNext.onclick = () => {
if (new Date() - lastTime < 1000) {
return; //两次点击小于1s,不做任何操作
}
lastTime = new Date();
index++;
unifromMotion(aImgs, { 'left': -imgWidth }, 500);
if (index >= len) {
index = 0;
setTimeout(function () {
aImgs.style.left = 0; //从最后一张替身直接回到第一张,替身达到无缝的效果
}, 1000) //1s后执行,因为轮播动画是异步,立刻执行这一句的话,异步的轮播动画会将left=0的效果覆盖掉
}
changeImg(index);
}
//为圆点绑定点击事件
for (let i = 0; i < len; i++) {
aDots[i].onclick = () => {
if (new Date() - lastTime < 1000) {
return; //两次点击小于1s,不做任何操作
}
lastTime = new Date();
let changeValue = (index - i) * imgWidth
unifromMotion(aImgs, { 'left': changeValue }, 500);
index = i;
changeImg(i);
}
}
//鼠标移入布局,停止轮播
oWarp.onmouseenter = () => {
clearInterval(timer);
}
//鼠标移出布局,开始轮播
oWarp.onmouseleave = () => {
clearInterval(timer);
timer = window.setInterval(oNext.onclick, 1500);
}
//改变当前显示的的图片和圆点
let changeImg = (index) => {
document.getElementsByClassName('checked')[0].className = ''; //清除当前选中的li点checked样式
aDots[index].className = 'checked'; //为对应的li点添加选中样式
}
//页面加载完毕1.5s后启动轮播
setTimeout(timer = window.setInterval(oNext.onclick, 1500), 1500);
总结
- 开始写的时候分别对上一张和下一张的点击事件以及自动播放分开写,看过别人的建议后,改为在定时器里定时调用下一张的点击事件。
- 将运动的动画和实现的逻辑分开写,开始写的时候混在一起写,出现各种解决不了的问题,bi如动画冲突的问题,导致动画播放不正常,搜集其他例子后,学着把运动动画和功能逻辑分开写,思路上和代码上都清晰了不少,功能也能很好的实现。
- 这个简单的例子只是用来练习,还可以进行更多的优化和升级,目前想法是,后期进行功能上的晚上,比如可以自定义上传图片,增加对应的接口等。
- 开始以为会很简单,写了之后才发现问题百出,写代码真的是不能眼高手低呀
附
匀速运动框架介绍:https://blog.csdn.net/DeepHugY/article/details/82146543