一.实现思路
实现效果:
1. css
将垂直排列的多张图片水平排列,可以使用浮动;或将包裹图片的盒子设置为行内块元素inline-block,并消除空白折叠。
2. js
1) 如何让图片水平移动?
将包裹所有图片的总容器设置为绝对定位,通过修改left属性展示需要的图片,切换left属性时一般使用过渡效果transition;
2) 首尾如何无缝切换图片?
在最后一张图片之后加上第一张轮播图,当显示添加的第一张轮播图后将left属性修改为真正第一张轮播图的left值,切换时取消过渡效果;同理在第一张轮播图之前加上最后一张轮播图...
3) 轮播图切换细节?
每次切换一张轮播图是以一张轮播图的宽度为单位,改变容器left值;通过设置全局属性index,指定偏离量,如:显示第一张图即index=1,left = '-' + index * picWidth + 'px',图片左移一张需要将index++,右移一张图片需要将index--。
4) 自动播放和圆点切换原理?
将左移一张图片和右移一张图片各封装成函数leftMoveSwiper()和rightMoveSwiper(),自动播放时设置定时器,定时执行leftMoveSwiper(),鼠标进入轮播图区域时取消定时器clearInterval(timer),改为手动切换模式;
随后获取圆点的下标索引,找到原点下标和index之间的对应关系,修改index值,随后调用一次leftMoveSwiper()切换到指定的位置。
5) 圆点切换如何使用事件委托?
使用事件委托,将点击事件绑定给原点的父容器wrapper,通过事件对象event.target获取点击的目标元素,通过event.target.classList.contains(‘指定类名’)判断是否为需要操作的目标元素(即圆点)。
3.代码
html部分:
<div class="app">
<ul class="wrapper">
<li class="liWrapper">
<a href="#" class="link">
<img src="./img/p5.jpg" alt="" class="img">
</a>
</li>
<li class="liWrapper">
<a href="#" class="link">
<img src="./img/p1.jpg" alt="" class="img">
</a>
</li>
<li class="liWrapper">
<a href="#" class="link">
<img src="./img/p2.jpg" alt="" class="img">
</a>
</li>
<li class="liWrapper">
<a href="#" class="link">
<img src="./img/p3.jpg" alt="" class="img">
</a>
</li>
<li class="liWrapper">
<a href="#" class="link">
<img src="./img/p4.jpg" alt="" class="img">
</a>
</li>
<li class="liWrapper">
<a href="#" class="link">
<img src="./img/p5.jpg" alt="" class="img">
</a>
</li>
<li class="liWrapper">
<a href="#" class="link">
<img src="./img/p1.jpg" alt="" class="img">
</a>
</li>
</ul>
<i class="iconfont icon-arrow-left"></i>
<i class="iconfont icon-arrow-right"></i>
<div class="dot">
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
</div>
<script src="./index.js"></script>
css部分:
* {
margin:0;
padding:0;
box-sizing:border-box;
/* overflow: hidden; */
}
.app{
position: absolute;
top:50%;
left:50%;
transform: translate(-50%,-50%);
height: 280px;
width: 520px;
overflow: hidden;
border-radius: 8px;
/* display: block; */
}
.app:hover .iconfont{
display:block;
}
.wrapper{
z-index:1;
display: block;
position: absolute;
list-style:none;
/* 处理空白折叠 */
font-size: 0;
}
.liWrapper{
display:inline-block;
}
.iconfont {
position:absolute;
z-index:2;
font-size:24px;
height:24px;
color: blanchedalmond;
background-color: rgba(0,0,0,0.3);
cursor:pointer;
display:none;
}
.icon-arrow-left{
top:50%;
left:-5px;
border-radius: 0 12px 12px 0;
transform:translateY(-50%);
}
.icon-arrow-right{
top:50%;
right:-5px;
border-radius: 11px 0 0 11px;
transform:translateY(-50%);
}
.dot {
z-index:2;
position:absolute;
bottom:15px;
left:50%;
transform: translateX(-50%);
background-color: rgba(255,255,255,.3);
border-radius: 6px;
font-size: 0;
}
.dot span {
display: inline-block;
width: 8px;
height: 8px;
margin: 3px;
border-radius: 4px;
background-color: #fff;
}
.dot-active {
background-color: #ff5500!important;
}
js部分:
let perWidth = 520; // 一张图片的宽度
let wrapper = document.querySelector('.wrapper');
let app = document.querySelector('.app');
let liWrapper = document.querySelectorAll('.liWrapper');
let dots = document.querySelector('.dot').children;
let preTime = 0; // 上一刻时间,处理防抖
wrapper.style.width = perWidth * liWrapper.length + 'px'; // 获取并设置图片容器的总宽度
// 当前是第几张图片
let index = 1;
// 定时器标识
let timer;
// wrapper 初始化
function swiperInit() {
wrapper.style.left = '-' + perWidth * index + 'px';
}
// 左移轮播图
function leftMoveSwiper() {
index ++;
wrapper.style.left = '-' + perWidth * index + 'px';
wrapper.style.transition = 'left 1s';
if(index >= liWrapper.length - 1) {
setTimeout(() => {
index = 1;
wrapper.style.transition = 'none';
wrapper.style.left = '-' + perWidth * index + 'px';
setDotColor();
},1000)
}
setDotColor();
}
// 右移轮播图
function rightMoveSwiper() {
index --;
wrapper.style.left = '-' + perWidth * index + 'px';
wrapper.style.transition = 'left 1s';
if(index <= 0) {
setTimeout(() => {
index = 5;
wrapper.style.transition = 'none';
wrapper.style.left = '-' + perWidth * index + 'px';
},1000)
}
setDotColor();
}
// 自动播放
function autoplaySwiper() {
timer = setInterval(() => {
leftMoveSwiper();
},2000);
}
// 事件绑定
function handleBind(){
// 利用事件委托,给箭头绑定点击事件
app.addEventListener('click',function(e){
if(e.target.classList.contains('icon-arrow-left')) {
throttle(rightMoveSwiper,1000);
} else if(e.target.classList.contains('icon-arrow-right')) {
throttle(leftMoveSwiper,1000);
}
});
// 鼠标进入暂停自动轮播
app.addEventListener('mouseenter',function(){
clearInterval(timer);
});
// 鼠标离开继续自动轮播
app.addEventListener('mouseleave',function(){
autoplaySwiper();
})
}
// 防抖处理
function throttle(fn,delay) {
let now = Date.now();
if(now - preTime >= delay) {
fn();
preTime = now;
}
}
// dot颜色设置
function setDotColor() {
for (let i = 0; i < dots.length; i++) {
if(index === i + 1){
dots[i].classList.add('dot-active');
} else {
dots[i].classList.remove('dot-active')
}
if(index === dots.length + 1) {
dots[0].classList.add('dot-active');
} else if(index === 0) {
dots[dots.length - 1].classList.add('dot-active');
}
}
}
// 点击原点切换轮播图
function pointDotChangePic(){
for (let i = 0; i < dots.length; i++) {
dots[i].addEventListener('click',function(){
index = i;
leftMoveSwiper();
})
}
}
// 初始化设置
function init(){
swiperInit();
autoplaySwiper();
handleBind();
setDotColor();
pointDotChangePic();
}
init();
二.问题
z-index无效原因
这种情况发生的条件有三个:
1、父标签 position属性为relative;
2、问题标签无position属性(不包括static);
3、问题标签含有浮动(float)属性。
空白折叠
display为inline的元素之间,若这些元素标签之间不写在同一行上,浏览器会在这些元素之间加上一格空白,空白大小视font-size值大小,去除空白只需将这些元素的共同父元素font-size值设置为0;
line-height 无效原因
已知父元素dots,子元素dot,子元素设为inline-block,为解决子元素出现的空白折叠,将父元素font-size设为0,此时为了让子元素垂直居中,设置line-height无效,原因是字体font-size为0
解决办法是将子元素的margin-top和margin-bottom设置为一个相同的值,如4px