工作中一直用别人的UI组件,突然要手写一个轮播图,搞得汗流浃背。
话不多说 Talk is cheap,show me the code!
样式就随便写了,这里主要讲如何实现和实现思路。
首先说一下什么是轮播图:
轮播图无非就是在视口中单独显示的一组图片,让其自动滚动或点击按钮滚动,其实就是改变他的位置。
专业术语是这么说的:无缝轮播图,即是在图片左右切换时,最后一张和第一张相连,也就是当主屏幕显示最后一张图片时,如果用户点击下一张图片时,这时候需要将第一张图片呈现给用户。 同理当目前主屏幕上显示第一张图片时,如果用户点击上一张图片时,需要将最后一张图片呈现给用户。
这里我通过transform实现。
css
css部分
.carousel-container {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
border: 10px solid #000;
/* overflow: hidden; */
}
.carousel-wrapper {
display: flex;
width: 300px;
height: 200px;
}
.carousel-item {
flex: 0 0 100%;
/* 一次显示一个轮播项 */
}
.carousel-item img {
width: 100%;
height: 100%;
object-fit: cover
}
ini
HTML部分
<div class="carousel-container">
<div class="carousel-wrapper">
<div class="carousel-item">
<img src="./images/3.png" alt="">
</div>
<div class="carousel-item">
<img src="./images/1.png" alt="">
</div>
<div class="carousel-item">
<img src="./images/2.jpg" alt="">
</div>
<div class="carousel-item">
<img src="./images/3.png" alt="">
</div>
<div class="carousel-item">
<img src="./images/1.png" alt="">
</div>
</div>
<button class="prev-button">Previous</button>
<button class="next-button">Next</button>
</div>
为了更好地看到效果,这里先把overflow: hidden;注释掉。 结构如图所示

接下来就是点击按钮让图片滚动了
ini
js部分
<script>
// 这里获取到需要操作的dom
const carouselWrapper = document.querySelector('.carousel-wrapper')
const carouselItems = document.querySelectorAll('.carousel-item')
const preButton = document.querySelector('.prev-button');
const nextButton = document.querySelector('.next-button');
// 一张轮播图的宽度
const itemWidth = carouselItems[0].clientWidth;
// 标志着当前显示第几张图片
let curIndex = 0;
// 初始化轮播图
function initCarousel() {
preButton.addEventListener('click', preButtonClick)
nextButton.addEventListener('click', nextButtonClick)
}
// 给pre按钮绑定click事件
function preButtonClick() {
// 往前一张滚动 自然是减-
curIndex = curIndex - 1;
// 过渡样式
carouselWrapper.style.transition = 'transform 0.3s ease-in-out'
// 当前一张没有图片时,我们直接让他定位到最后一张去,实现无缝轮播效果。
if (curIndex < 0) {
curIndex = carouselItems.length - 1;
// 这里把过渡样式设置为none,原因是滚动到最后一张时,会出现其他图片,设为none,就是一瞬间的事。
carouselWrapper.style.transition = 'none';
}
// 进行滚动
showItem(curIndex)
}
// next按钮其实逻辑上没什么区别
function nextButtonClick() {
curIndex = curIndex + 1;
carouselWrapper.style.transition = 'transform 0.3s ease-in-out'
// 如果是最后一张,就让他滚到第一张去。
if (curIndex === carouselItems.length) {
curIndex = 0
carouselWrapper.style.transition = 'none'
}
showItem(curIndex)
}
function showItem(index) {
carouselWrapper.style.transform = `translateX(-${itemWidth * index}px)`
}
initCarousel()
</script>
好 现在看下效果。(gif图看着很卡,不知道什么情况)

效果是实现了,但是大家应该也发现了,正常滚动是有过渡动画的,可第一张点击pre或者是最后一张next到第一张,是瞬间完成的,这是因为我们把transition设置为none的原因。
我觉得不太行,有点生硬,应该是都有过渡效果才对。
代码改造
xml
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<style>
.carousel-container {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
border: 10px solid #000;
/* overflow: hidden; */
}
.carousel-wrapper {
display: flex;
width: 300px;
height: 200px;
}
.carousel-item {
flex: 0 0 100%;
/* 一次显示一个轮播项 */
}
.carousel-item img {
width: 100%;
height: 100%;
object-fit: cover
}
</style>
<body>
<div class="carousel-container">
<div class="carousel-wrapper">
<div class="carousel-item">
<img src="./images/3.png" alt="">
</div>
<div class="carousel-item">
<img src="./images/1.png" alt="">
</div>
<div class="carousel-item">
<img src="./images/2.jpg" alt="">
</div>
<div class="carousel-item">
<img src="./images/3.png" alt="">
</div>
<div class="carousel-item">
<img src="./images/1.png" alt="">
</div>
</div>
<button class="prev-button">Previous</button>
<button class="next-button">Next</button>
</div>
<script>
const carouselWrapper = document.querySelector('.carousel-wrapper')
const carouselItems = document.querySelectorAll('.carousel-item')
const preButton = document.querySelector('.prev-button');
const nextButton = document.querySelector('.next-button');
const itemWidth = carouselItems[0].clientWidth;
let curIndex = 0;
// 初始化轮播图
function initCarousel() {
preButton.addEventListener('click', preButtonClick)
nextButton.addEventListener('click', nextButtonClick)
showItem(++curIndex)
}
function preButtonClick() {
curIndex = curIndex - 1;
carouselWrapper.style.transition = 'transform 0.3s ease-in-out';
if (curIndex === 0) {
setTimeout(() => {
carouselWrapper.replaceChildren(...carouselItems);
carouselWrapper.style.transition = 'none';
curIndex = carouselItems.length - 2
showItem(curIndex)
}, 300);
}
showItem(curIndex)
}
function nextButtonClick() {
curIndex = curIndex + 1;
carouselWrapper.style.transition = 'transform 0.3s ease-in-out';
if (curIndex === carouselItems.length - 1) {
setTimeout(() => {
carouselWrapper.replaceChildren(...carouselItems);
carouselWrapper.style.transition = 'none';
curIndex = 1
showItem(curIndex)
}, 300);
}
showItem(curIndex)
}
function showItem(index) {
carouselWrapper.style.transform = `translateX(-${itemWidth * index}px)`
}
initCarousel()
</script>
</body>
</html>
这里直接给上所有代码,差异如下:
1.首先样式是不用变得
2.先看结构,头和尾分别先放置了尾和头。
3.舒适化轮播图initCarousel,多了一行代码showItem(++curIndex),为的就是像原来一样正常显示第一张(因为我们在头部加了一张尾部图片嘛,所以 +1 )
4.在按钮监听事件,我挑一个说(preButtonClick),点击后上一张是尾图时进行判断(可以理解为进来直接点pre按钮,这里主要做了三件事
1.替换页面元素, 这里建议自己画下图好理解
2.清除过渡效果
3.移动轮播图位置
这三件事,用户是感知不到的,下面看下最终效果

这动图好卡啊 - -!
ok现在已经都有过渡效果了。