原生
1. index.html
- 图片 ul>li
- 点标记 ul>li
<div class="jd_layout">
<!--轮播图-->
<div class="jd_banner">
<!--图片-->
<ul class="jd_bannerImg clearfix">
<li>
<a href="javascript:;">
<img src="images/l1.jpg" alt="">
</a>
</li>
<li>
<a href="javascript:;">
<img src="images/l2.jpg" alt="">
</a>
</li>
<li>
<a href="javascript:;">
<img src="images/l3.jpg" alt="">
</a>
</li>
<li>
<a href="javascript:;">
<img src="images/l4.jpg" alt="">
</a>
</li>
<li>
<a href="javascript:;">
<img src="images/l5.jpg" alt="">
</a>
</li>
<li>
<a href="javascript:;">
<img src="images/l6.jpg" alt="">
</a>
</li>
<li>
<a href="javascript:;">
<img src="images/l7.jpg" alt="">
</a>
</li>
<li>
<a href="javascript:;">
<img src="images/l8.jpg" alt="">
</a>
</li>
</ul>
<!--点标记-->
<ul class="jd_bannerIndicator">
<li class="active"></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</div>
</div>
2.步骤
2.1 修改轮播图的页面结构
- 克隆第一张和最后一张图,实现无缝转接
imgBox.appendChild(first.cloneNode(true));
imgBox.insertBefore(last.cloneNode(true),imgBox.firstChild);
2.2 设置对应的样式
- 获取轮播图显示区域的宽度
bannerWidth
- 遍历每一个li,设置宽为
bannerWidth
- 设置所有li排列在一行的宽
imgBox
=bannerWidth
* li的个数 + ‘px’
var lis=imgBox.querySelectorAll("li");
var count=lis.length;
var bannerWidth=banner.offsetWidth;
imgBox.style.width=count*bannerWidth+"px";
for(var i=0;i<lis.length;i++){
lis[i].style.width=bannerWidth+"px";
}
2.3 设置默认偏移
- 因为之前将最后一张克隆到了最前面,所以需要设置偏移
imgBox.style.left=-bannerWidth+"px";
2.4 屏幕变化更改宽度
- 使用
window.onresize
监听 - 重复之前设置样式的步骤
- 注意
bannerWidth
不需要再声明var
- 注意
- 再次设置默认偏移
/*4.当屏幕变化的时候,重新计算宽度*/
window.onresize=function(){
bannerWidth=banner.offsetWidth;
imgBox.style.width=count*bannerWidth+"px";
for(var i=0;i<lis.length;i++){
lis[i].style.width=bannerWidth+"px";
}
imgBox.style.left=-index*bannerWidth+"px";
}
2.5 实现点标记
- 要达到同步效果需让图片的索引和点的索引一致
- 调用封装好的方法传入当前图片的索引
- 初始图片索引为1,点的初始索引为0
- 让图片和点的索引对应,需将图片的索引减去1
- 获取所有点标记的li移除
active
样式 - 当前li设置
active
样式
/*5.实现点标记*/
var index = 1
var setIndicator=function(index){
var indicators=banner.querySelector("ul:last-of-type").querySelectorAll("li");
for(var i=0;i<indicators.length;i++){
indicators[i].classList.remove("active");
}
indicators[index-1].classList.add("active");
};
2.6 实现自动轮播
- 使用定时器
index++
- 设置新的偏移
(-index*bannerWidth)+"px"
- 如果图片轮播到最后一张,后续继续轮播会没有图片,所以应该重新跳转到第二张
/*6.实现自动轮播*/
var startTime=function(){
timerId=setInterval(function(){
index++;
imgBox.style.transition="left 0.5s ease-in-out";
imgBox.style.left=(-index*bannerWidth)+"px";
setTimeout(function(){
if(index==count-1){
//轮播到最后一张
index=1;
imgBox.style.transition="none";
imgBox.style.left=(-index*bannerWidth)+"px";
}
},500);
},1000);
}
startTime();
2.7 实现手动轮播
touchstart
- 清除轮播的定时器
imgBox.addEventListener("touchstart",function(e){
clearInterval(timerId);
startX= e.targetTouches[0].clientX;
});
touchmove
- 计算两点之间X轴距离
distanceX
- 设置新偏移 = 原偏移+
distanceX
- 开启定时器的时候添加了过渡效果,在touchmove的时候没有清除这个过渡也就导致那个延迟了,解决的办法是在touchmove事件中清除过渡
imgBox.addEventListener("touchmove",function(e){
if(isEnd==true){
console.log("touchmove");
moveX= e.targetTouches[0].clientX;
//计算距离
distanceX=moveX-startX;
//清除过渡
imgBox.style.transition="none";
//设置偏移
imgBox.style.left=(-index*bannerWidth + distanceX)+"px";
}
});
touchend
-
若移动距离小于给定的值则状态不变
-
否则判断左移还是右移,修改相应的
index
并设置相应的偏移 -
起始位置和移动距离归零
imgBox.addEventListener("touchend",function(e){
isEnd=false;
if(Math.abs(distanceX) > 100){
if(distanceX > 0){//上一张
index--;
}
else{ //下一张
index++;
}
imgBox.style.transition="left 0.5s ease-in-out";
imgBox.style.left=-index*bannerWidth+"px";
}
else if(Math.abs(distanceX) > 0){
imgBox.style.transition="left 0.5s ease-in-out";
imgBox.style.left=-index*bannerWidth+"px";
}
//初始化
startX=0;
moveX=0;
distanceX=0;
});
webkitTransitionEnd
- webkitTransitionEnd:当过渡效果执行完成以后执行这个事件
- 当从一张图片滑动到结束的图片,再继续滑动会出现空白
imgBox.addEventListener("webkitTransitionEnd",function(){
//最后一张时
if(index==count-1){
index=1;
imgBox.style.transition="none";
imgBox.style.left=-index*bannerWidth+"px";
}
else if(index==0){
//第一张时
index=count-2;
imgBox.style.transition="none";
imgBox.style.left=-index*bannerWidth+"px";
}
setIndicator(index);
isEnd=true;
});
3. 出现过的bug
3.1 快速滑动会出现空白的
- 原因:当前滑动距离超过100,图片完成过渡效果需0.5s,这时用户又接着多次滑动就导致此时的transitionEnd没有触发,从而就导致了空白问题
- 解决:使用节流阀进行拦截(如果当前有人在办理业务,就把这个拉上,等办完了再打开)
- 步骤:
- 初始一个全局变量 设置其值为true
- 在touchmove事件判断阀门是否开启
3.2 无法滑到下一张
- 原因:touchmove和transitionEnd都没有触发轮播图却还可以滑动轮播 就是touchend在触发,因为上一次的touchmove虽然没在被触发,但touchmove中的distance值却存在导致后面滑动的distance是一个固定值。
- 解决:对每次触摸后的值进行初始化为0
4. JS代码
window.onload=function(){
bannerEffect();
}
function bannerEffect(){
/*1.设置修改轮播图的页面结构*/
var banner=document.querySelector(".jd_banner");
var imgBox=banner.querySelector("ul:first-of-type");
var first=imgBox.querySelector("li:first-of-type");
var last=imgBox.querySelector("li:last-of-type");
imgBox.appendChild(first.cloneNode(true));
imgBox.insertBefore(last.cloneNode(true),imgBox.firstChild);
/*2.设置对应的样式*/
var lis=imgBox.querySelectorAll("li");
var count=lis.length;
var bannerWidth=banner.offsetWidth;
imgBox.style.width=count*bannerWidth+"px";
for(var i=0;i<lis.length;i++){
lis[i].style.width=bannerWidth+"px";
}
var index=1;
/*3.设置默认的偏移*/
imgBox.style.left=-bannerWidth+"px";
/*4.当屏幕变化的时候,重新计算宽度*/
window.onresize=function(){
bannerWidth=banner.offsetWidth;
imgBox.style.width=count*bannerWidth+"px";
for(var i=0;i<lis.length;i++){
lis[i].style.width=bannerWidth+"px";
}
imgBox.style.left=-index*bannerWidth+"px";
}
/*5.实现点标记*/
var setIndicator=function(index){
var indicators=banner.querySelector("ul:last-of-type").querySelectorAll("li");
for(var i=0;i<indicators.length;i++){
indicators[i].classList.remove("active");
}
indicators[index-1].classList.add("active");
};
var timerId;
/*6.实现自动轮播*/
var startTime=function(){
timerId=setInterval(function(){
index++;
imgBox.style.transition="left 0.5s ease-in-out";
imgBox.style.left=(-index*bannerWidth)+"px";
setTimeout(function(){
if(index==count-1){
index=1;
imgBox.style.transition="none";
imgBox.style.left=(-index*bannerWidth)+"px";
}
},500);
},1000);
}
startTime();
/*7.实现手动轮播*/
var startX,moveX,distanceX;
var isEnd=true;
imgBox.addEventListener("touchstart",function(e){
clearInterval(timerId);
startX= e.targetTouches[0].clientX;
});
imgBox.addEventListener("touchmove",function(e){
if(isEnd==true){
console.log("touchmove");
moveX= e.targetTouches[0].clientX;
distanceX=moveX-startX;
imgBox.style.transition="none";
imgBox.style.left=(-index*bannerWidth + distanceX)+"px";
}
});
imgBox.addEventListener("touchend",function(e){
isEnd=false;
if(Math.abs(distanceX) > 100){
if(distanceX > 0){//上一张
index--;
}
else{ //下一张
index++;
}
imgBox.style.transition="left 0.5s ease-in-out";
imgBox.style.left=-index*bannerWidth+"px";
}
else if(Math.abs(distanceX) > 0){
imgBox.style.transition="left 0.5s ease-in-out";
imgBox.style.left=-index*bannerWidth+"px";
}
startX=0;
moveX=0;
distanceX=0;
});
imgBox.addEventListener("webkitTransitionEnd",function(){
if(index==count-1){
index=1;
imgBox.style.transition="none";
imgBox.style.left=-index*bannerWidth+"px";
}
else if(index==0){
index=count-2;
imgBox.style.transition="none";
imgBox.style.left=-index*bannerWidth+"px";
}
setIndicator(index);
isEnd=true;
});
}
zepto实现轮播图
1. 步骤
- 添加首尾两张图片
- 重新设置盒子的宽度和图片的宽度
- 开启定时器,实现自动轮播
- 添加移动端的滑动事件,实现手动轮播
- 添加过渡效果结束之后的监听
2. 代码
$(function(){
// 获取轮播图元素
var banner = $('.jd_banner');
var bannerWidth = banner.width();
//获取图片盒子
var imgBox = banner.find('ul:first-of-type');
//获取点标记
var indicators = banner.find("ul:eq(1)").find("li");
//获取首尾两张图片
var first = imgBox.find('li:first-of-type');
var last = imgBox.find('li:last-of-type');
//将两张图片添加到首层位置 first.clone():将first拷贝一份
imgBox.append(first.clone());
last.clone().insertBefore(first);
//设置图片盒子的宽度
var lis = imgBox.find('li');
var count = lis.length;
imgBox.width(count * bannerWidth);
//设置li标签的宽度
lis.each(function(index,value){
$(lis[index]).width(bannerWidth)
});
//设置默认偏移
imgBox.css('left',-bannerWidth);
//定义图片索引
var index = 1;
//开启定时器
setInterval(function(){
index++;
imgBox.animate({"left":-index * bannerWidth},200,'ease-in-out',function(){
if(index == count - 1){//最后一张
index = 1;
//让它瞬间偏移到索引1的位置 -- 非过渡
imgBox.css('left',-index * bannerWidth);
}else if(index == 0){
index = count - 2;
imgBox.css('left',-index * bannerWidth);
}
//设置点标记
indicators.removeClass('active').eq(index-1).addClass('active');
})
},2000)
//添加滑动事件
+ imgBox.on('swipeLeft',function(){
+ console.log('swipeLeft');
+ })
+ imgBox.on('swipeRight',function(){
+ console.log('swipeRight');
+ })
+ })
Swiper
- Swiper4.x使用方法
- Swiper Animate使用方法
- Vue中使用Swiper
MUI
- gallery
NUTUI
- 有滑动懒加载图片功能
Mint-UI
- swipe