HTML代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
.focus {
position: relative;
overflow: hidden;
/* margin-top: 44px; */
}
.focus img {
/* 设置这个属性的目的是,去除.focus不设置高度时,由img撑开的 div下面多余的4px,但是本项目可以不用设置 */
/* display: block; */
width: 100%;
}
.focus ul {
overflow: hidden;
width: 500%;
margin-left: -100%;
/* 因为要做无缝衔接,导致没做无缝衔接前的最后一张图会显示在第一张,所以要往左移动父亲宽度的100%,使得第一张默认在第一个 */
}
.focus ul li {
float: left;
width: 20%;
}
.circle {
position: absolute;
right: 10px;
bottom: 5px;
margin: 0;
}
.circle li {
display: inline-block;
width: 5px;
height: 5px;
border-radius: 2px;
background-color: skyblue;
transition: all .3s;
/* list-style: none; */
}
.circle li.current {
width: 15px;
}
</style>
<script src="js/index.js"></script>
</head>
<body>
<div class="focus">
<ul>
<!-- ********************轮播图无缝衔接↓******************** -->
<li>
<img src="./upload/focus3.jpg" alt="">
</li>
<!-- ********************↑******************** -->
<li>
<img src="./upload/focus.jpg" alt="">
</li>
<li>
<img src="./upload/focus2.jpg" alt="">
</li>
<li>
<img src="./upload/focus3.jpg" alt="">
</li>
<!-- ********************轮播图无缝衔接↓******************** -->
<li>
<img src="./upload/focus.jpg" alt="">
</li>
<!-- ********************↑******************** -->
</ul>
<!-- 小圆点 -->
<ol class="circle">
<li class="current"></li>
<li></li>
<li></li>
</ol>
</div>
</body>
</html>
index.js代码
// 移动端实现轮播图效果是通过translateX+transition实现
window.addEventListener('load', function () {
let focus = document.querySelector('.focus') // 轮播图整个区域
let ul = focus.children[0] // 轮播图区域
let ol = focus.children[1] // 小圆点区域
let w = focus.offsetWidth // 轮播图的可视宽度
let index = 0 // 定义当前轮播图的索引值
let timer = setInterval(() => {
index++
let translateX = -index * w //当前图片要移动的位置
ul.style.transition = 'all .2s' // 加上过渡效果
ul.style.transform = 'translateX(' + translateX + 'px)'
}, 2000);
ul.addEventListener('transitionend', function () { // 每次transition动画刚结束就会触发此事件
if (index >= 3) {
// 当图片轮播到最后一张的时候(这里的最后一张是之前做无缝衔接在最后新增的实际第一张图片),
// 迅速将索引值恢复到初始值,在恢复的时候先取消动画(为了做到无缝衔接的效果,因为是瞬间的事)
index = 0
ul.style.transition = 'none'
let translateX = -index * w
ul.style.transform = 'translateX(' + translateX + 'px)'
} else if (index < 0) {
// 这里是当手指右滑的时候,如果划到第一张时(这里的第一张是做无缝衔接时加的最后一张图片内容)
index = 2; // 这里为什么是 2,当用户划到最后一张图片时,下一次index++就是倒数第二张了呀
ul.style.transition = 'none';
// 利用最新的索引号乘以宽度 去滚动图片
let translateX = -index * w;
ul.style.transform = 'translateX(' + translateX + 'px)';
}
// 小圆点变化
// 1. 移除先前的current
ol.querySelector('li.current').classList.remove('current')
// 2. 再把现在索引号对应的li加上current
ol.children[index].classList.add('current')
})
// 手指滑动轮播图
let startX = 0 // 初始化手指开始时的位置
let moveX = 0 // 手指滑动时DOM元素要移动的距离
let flag = false // 标记手指放在DOM元素上是否移动过
ul.addEventListener('touchstart', function (e) { // 手指刚放在DOM元素上时触发
startX = e.targetTouches[0].pageX // 获取到刚放去的手指位置
clearInterval(timer) // 手指放上去就停止定时器(轮播)
})
ul.addEventListener('touchmove', function (e) { // 手指滑动时触发
moveX = e.targetTouches[0].pageX - startX // 用手指滑动之后停留在某处的位置减去手指刚放去的位置就是手指移动的距离
let translateX = -index * w + moveX
ul.style.transition = 'none' // 手指滑动时不需要动画
ul.style.transform = 'translateX(' + translateX + 'px)'
flag = true // 如果用户手指移动过,再去判断
e.preventDefault() // 阻止滚动屏幕的行为
})
ul.addEventListener('touchend', function (e) { // 手指松开瞬间触发
if (flag) {
// 判断手指滑动的距离来决定图片的播放
if (Math.abs(moveX) > 50) {
// 如果大于50px就播放上一张或者下一张
if (moveX > 0) {
// 如果是右滑,上一张
index--
} else {
// 如果是左滑,下一张
index++
}
let translateX = -index * w
ul.style.transition = 'all .2s'
ul.style.transform = 'translateX(' + translateX + 'px)'
} else {
// 小于50px就回弹
let translateX = -index * w
ul.style.transition = 'all .5s'
ul.style.transform = 'translateX(' + translateX + 'px)'
}
flag = false // 还原标记
}
// 手指离开之后再开启定时器
clearInterval(timer)
timer = setInterval(() => {
index++
let translateX = -index * w
ul.style.transition = 'all .2s'
ul.style.transform = 'translateX(' + translateX + 'px)'
}, 2000);
})
})
上述代码需要优化,这里没做修改是为了便于理解原理
代码粘贴到项目中可直接食用哦!