一、前言
手撸系列又来啦,这次我们实现的是carousel组件(又叫轮播图),这个组件的使用率非常的高,这次我们就来撸他。
二、效果
三、实现的功能清单
- 手动切换
- 自动切换(下篇再讲)
四、逐个击破
4.1、静态界面
在做切换的功能之前,我们先来分析一下它的静态界面:
由上图我们可知,整个组件其实就分为2个部分:
- 内容组件
- 活动指示器
现在整体的框架已经出来了,接下来就是一步一步先把静态页面搭起来。
<style>
.carousel-content-list {
width: fit-content;
height: fit-content;
display: flex;
box-sizing: border-box;
}
.carousel-box-item {
width: 200px;
height: 100px;
display: flex;
flex-shrink: 0;
align-items: center;
justify-content: center;
background-color: rgb(54, 77, 121);
color: rgb(255, 255, 255);
box-sizing: border-box;
}
</style>
<div class='carousel-box'> <!-- 组件最外围的box -->
<div class="carousel-content-list"> <!-- 存放轮播图的box -->
<div class="carousel-box-item carousel-box-one">1</div>
<div class="carousel-box-item carousel-box-two">2</div>
<div class="carousel-box-item carousel-box-three">3</div>
</div>
</div>
此时的静态效果应该是这样的:
接下来我们来处理活动指示器。活动指示器有个特点,就是轮播图无论如何切换,活动指示器的位置都不变。
说到位置不变,我们可以使用绝对定位来做到这样的功能。
代码如下:
<div class='carousel-box'> <!-- 组件最外围的box -->
<div class="carousel-content-list"> <!-- 存放轮播图的box -->
<div class="carousel-box-item carousel-box-one">1</div>
<div class="carousel-box-item carousel-box-two">2</div>
<div class="carousel-box-item carousel-box-three">3</div>
</div>
<div class="carousel-slick"> <!-- 活动指示器的box -->
<div class="carousel-dot carousel-dot-one"></div>
<div class="carousel-dot carousel-dot-two"></div>
<div class="carousel-dot carousel-dot-three"></div>
</div>
</div>
<style>
.carousel-box {
position: relative;
width: fit-content;
height: fit-content;
box-sizing: border-box;
}
.carousel-content-list {
width: fit-content;
height: fit-content;
display: flex;
box-sizing: border-box;
}
.carousel-box-item {
width: 200px;
height: 100px;
display: flex;
flex-shrink: 0;
align-items: center;
justify-content: center;
background-color: rgb(54, 77, 121);
color: rgb(255, 255, 255);
box-sizing: border-box;
}
.carousel-slick {
z-index: 100;
left: 0px;
right: 0px;
bottom: 12px;
position: absolute;
display: flex;
justify-content: center;
gap: 5px;
}
.carousel-dot {
width: 16px;
height: 3px;
background-color: #fff;
opacity: 0.3;
box-sizing: border-box;
transition: all .3s;
}
</style>
现在的效果大致是这样:
现在我们要处理一下轮播图显示的数量,一个轮播图组件每次应该只显示一张图,根据我们上面的div结构可知,carousel-content-list 元素的宽度是fit-content[也就是宽度等于图片数量宽度之和],那么我们只需要在 carousel-content-list 元素的外围加上一个类名为 carousel-content 的元素,然后让这个元素的宽度是一张图片的宽度,overflow置为hidden即可。代码如下:
<div class="carousel-box">
<div class="carousel-content">
<div class="carousel-content-list">
<div class="carousel-box-item carousel-box-one">1</div>
<div class="carousel-box-item carousel-box-two">2</div>
<div class="carousel-box-item carousel-box-three">3</div>
</div>
</div>
<div class="carousel-slick">
<div class="carousel-dot carousel-dot-one"></div>
<div class="carousel-dot carousel-dot-two"></div>
<div class="carousel-dot carousel-dot-three"></div>
</div>
</div>
<style>
// ...其他样式不变
.carousel-content {
width: 200px;
height: 100px;
box-sizing: border-box;
overflow: hidden;
}
.carousel-box-item {
width: 200px;
height: 100px;
display: flex;
flex-shrink: 0;
align-items: center;
justify-content: center;
background-color: rgb(54, 77, 121);
color: rgb(255, 255, 255);
box-sizing: border-box;
}
</style>
到目前为止,我们的静态页面已经写完,样子如下:
4.2、手动切换
功能点如下:
- 点击相应指示器,切换到相应轮播图
- 切换过程中,指示器整体的box不变
我们还是来看下整体结构,这样会清晰很多:
<div class="carousel-box"> <!-- 轮播图整体box -->
<div class="carousel-content"> <!-- 显示轮播图的窗口,并且位置是固定的 -->
<div class="carousel-content-list"> <!-- 存放所有的轮播图,切换主要是改变这个元素box的translateX -->
<div class="carousel-box-item carousel-box-one">1</div>
<div class="carousel-box-item carousel-box-two">2</div>
<div class="carousel-box-item carousel-box-three">3</div>
</div>
</div>
<div class="carousel-slick"> <!-- 活动指示器box -->
<div class="carousel-dot carousel-dot-one"></div>
<div class="carousel-dot carousel-dot-two"></div>
<div class="carousel-dot carousel-dot-three"></div>
</div>
</div>
实现思路:
相信上面的图已经非常明了的解释了手动切换的精髓(就是动态的改变carousel-content-list元素的translateX)。
实现总结:
1、初始化2个变量a(记录当前展示的轮播图的位置)、b(记录当前点击的指示器的位置)。
2、如果 a != b,说明当前要切换轮播图。
3、如果 a < b,说明即将切换的轮播图的位置一定在后面,carousel-content-list元素一定要向左滑动。
4、如果 a > b, 说明即将切换的轮播图的位置一定在前面,carousel-content-list元素一定要向右滑动。
代码如下:
let curPanelIndex = 1; // 当前面板的位置
let curclickedPanelIndex = 1; // 当前点击的指示器的位置
let allDistance = 0; // 滑动的总距离
function clickDot(event){
let target = event.target; // 点击的元素,利用事件委托
let curClickedElementClassList = Array.from(target.classList); // 当前点击元素的样式集合
let contentList = document.querySelector('.carousel-content-list'); // 滑动容器
let dotList = Array.from(document.querySelectorAll('.carousel-dot')); // 指示器集合
if (curClickedElementClassList.includes('carousel-dot-one')){ // 说明点击的是第一个图片的活动指示器
if (curPanelIndex == 1){
return
}
curclickedPanelIndex = 1;
} else if(curClickedElementClassList.includes('carousel-dot-two')){ // 说明点击的是第二个图片的活动指示器
if (curPanelIndex == 2){
return
}
curclickedPanelIndex = 2;
} else if (curClickedElementClassList.includes('carousel-dot-three')){
// three的情况就交给大家了, 哈哈哈
}
let distance = (curclickedPanelIndex - curPanelIndex) * 200;
if (curclickedPanelIndex - curPanelIndex < 0){
allDistance = allDistance + Math.abs(distance);
contentList.style.transform = 'translateX(' + allDistance + 'px)';
} else {
allDistance = allDistance - Math.abs(distance);
contentList.style.transform = 'translateX(' + allDistance + 'px)';
}
dotList.forEach((item, index) => {
if (index + 1 == curclickedPanelIndex){
item.classList.add('carousel-dot-click');
} else {
item.classList.remove('carousel-dot-click');
}
});
curPanelIndex = curclickedPanelIndex;
}
html代码改动如下:
<div class="carousel-slick" onclick="clickDot(event)"> <!-- 活动指示器box -->
<div class="carousel-dot carousel-dot-one"></div>
<div class="carousel-dot carousel-dot-two"></div>
<div class="carousel-dot carousel-dot-three"></div>
</div>
到目前为止,我们就实现了基本的轮播图(手动切换),下一篇我们来讲解自动切换的轮播图。
五、最后
好啦,这次的手撸系列到这里就结束啦。最近建立了一个原生实现组件专栏,目的是带着大家手把手实现市面上的所有组件,欢迎点赞关注。