使用 JavaScript 创建平滑的无限多项目轮播滑块



我正在使用克隆技术与翻译使用Javascript创建一个滑块。以下是工作示例:-

var fragPre = document.createDocumentFragment(),
fragPost = document.createDocumentFragment(),
clonedPre, clonedPost,
selectSlide = document.getElementById("numberOfSlides"),
//options
numberOfSlides = 3;
var items   = document.querySelectorAll("#gallery .slider-scroller-inner .item"),
len     = items.length,
current = 1,  /* the current item we're looking */
wrapper = document.getElementById("wrapper"),
transformVal = 0;
/* 1. Cloning last items and appending to first */  
for(var i=numberOfSlides ; i > 0 ; i--) {
clonedPre = items[items.length-i].cloneNode(true);
fragPre.append(clonedPre);
}
wrapper.insertBefore(fragPre , items[0]);
/* . Cloning first items and appending to first */  
for(var j = 0 ; j <= numberOfSlides-1 ; j++) {
clonedPost = items[j].cloneNode(true);
fragPost.append(clonedPost);
}
wrapper.appendChild(fragPost);
/* Slider arrow click function */  
var slideWidth=items[0].offsetWidth;
var counter = 0;
var timer = null;
var timeout = null;
wrapper.style.transform = "translate3d(" + (-slideWidth) * (numberOfSlides) + "px,0,0)";
function arrowClick(dir) {
clearTimeout(timeout);
timeout = setTimeout(function() {
counter = 0;
direction = dir;
var str = wrapper.style.transform;
var left = str.substring(12, str.length - 11);
console.log(left);
animateSlide(current, left);
}, 300);
}
/* slide number click function */  
function changeCurrent(curr) {
current = curr;
wrapper.style.transform =  "translate3d(" + -(slideWidth) * (current + (numberOfSlides-1)) + "px,0,0)";
}
/* actual sliding effect */  
function animateSlide(curr, left) {
var timer = setInterval(function() {
if(counter < slideWidth) {
transformVal = parseInt(left, 10) + (-(++counter) * direction);
wrapper.style.transform = "translate3d(" + transformVal + "px,0,0)";
} else {
current += direction;
cycle = !!(current === 0 || current > len);
if (cycle) {
current = (current === 0)? len : 1;
wrapper.style.transform ="translate3d(" + (-(slideWidth) * (current + (numberOfSlides-1))) + "px,0,0)";
}
counter = 0;
clearInterval(timer);
}
}, 0);  
}
body {
margin: 0;
padding: 0;
}
.carousel-slider-wrapper {
width: 1200px;
margin: 0 auto;
position: relative;
}
.slider-scroller-wrap {
overflow: hidden;
}
.slider-scroller {
font-size: 0;
white-space: nowrap;
position: relative;
top: 0;
margin: 0;
padding: 0;
}
.slider-scroller-inner {
/* transition: .2s ease-out; */

}
.slider-scroller-inner {
display: flex;
width: 100%;
position: relative;
}
.slider-scroller-inner .item {
display: inline-block;
vertical-align: top;
/* padding: 2px; */
box-sizing: border-box;
/* border: 1px solid; */
cursor: grab;
text-align: center;
flex: 0 0 33.33%;
}
.slider-scroller-inner .item img {
max-width: 100%;
}
button {
font: 40px "Courier New";
border: none;
box-shadow: 1px 2px 3px #666666;
background: #e4e4e4;
color: #626262;
cursor: pointer;
text-align: center;
position: absolute;
top: 50%;
transform: translateY(-50%);
height: 70px;
z-index: 1;
}
button.prev {
left: 0;
}
button.next {
right: 0;
}
label, a {
font: 14px Georgia;
font-style: italic;
color: #626262;
}
#indicators {
padding: 0;
margin: 1rem 0;
overflow: hidden;
text-align: center;
}
#indicators li {
padding: .5rem;
border-radius: 100%;
font-weight: bold;
background: #7592bd;
display: inline-flex;
height: 1.4rem;
width: 1.4rem;
color: #FFFFFF;
text-align: center;
cursor: pointer;
justify-content: center;
align-items: center;
margin-right: .3rem;
}
#indicators li:hover {
box-shadow: 1px 2px 3px #333333;
}
<div class="carousel-slider-wrapper">
<button class="prev" type="button" id="prev" onclick="arrowClick(-1)">&lsaquo;</button>
<div class="slider-scroller-wrap">
<div class="slider-scroller" id="gallery"> <!-- mask -->            
<div class="slider-scroller-inner" id="wrapper"> 
<div class="item"><img src="https://newyse-res.cloudinary.com/image/upload///t_mcms_larger/f_auto/v1511188164/33-2426430.jpg"></div>
<div class="item"><img src="https://newyse-res.cloudinary.com/image/upload///t_mcms_larger/f_auto/v1511186177/33-2425761.jpg"></div>
<div class="item"><img src="https://newyse-res.cloudinary.com/image/upload///t_mcms_larger/f_auto/v1511186164/33-2425751.jpg"></div>
<div class="item"><img src="https://newyse-res.cloudinary.com/image/upload///t_mcms_larger/f_auto/v1511185761/33-2425646.jpg"></div>
<div class="item"><img src="https://newyse-res.cloudinary.com/image/upload///t_mcms_larger/f_auto/v1557227665/33-2893456.jpg"></div>
<div class="item"><img src="https://newyse-res.cloudinary.com/image/upload///t_mcms_larger/f_auto/v1511970254/33-2437550.jpg"></div>
</div>    
</div>  
</div>
<button  class="next" type="button" id="next" onclick="arrowClick(1)">&rsaquo;</button>
</div>
<ul id="indicators" class="">
<li onclick="changeCurrent(1)">1</li>
<li onclick="changeCurrent(2)">2</li>
<li onclick="changeCurrent(3)">3</li>
<li onclick="changeCurrent(4)">4</li>
<li onclick="changeCurrent(5)">5</li>
<li onclick="changeCurrent(6)">6</li>
</ul>
以下是我正在遵循的步骤:-

  1. 我正在克隆最后几个项目并附加到第一个项目,克隆前几个项目并将其附加到最后一个(感谢帖子:- http://stackoverflow.com/a/15877302/1098851(。只是为了在我处于第一个或最后一个项目时产生无限的效果。

  2. 单击箭头时,我正在以与项目大小相同的方式转换项目容器,考虑到我正在转换的一侧。

  3. 在设置间隔内,我正在检查它的第一个项目还是最后一个项目,并相应地移动我的滑动容器。

上面的代码工作正常。只是我遇到了设置间隔功能的问题:- 1.它正在非常缓慢地改变幻灯片。

  1. 如果我多次单击箭头,幻灯片上会发生奇怪的效果。

你只需要更好地管理timeout

对于动画,使用CSS更合适:

transition: all 0.5s;会做好这项工作。

我更新了您的示例

注释中的说明

var fragPre = document.createDocumentFragment(),
fragPost = document.createDocumentFragment(),
clonedPre, clonedPost,
selectSlide = document.getElementById("numberOfSlides"),
//options
numberOfSlides = 3;
var items   = document.querySelectorAll("#gallery .slider-scroller-inner .item"),
len     = items.length,
current = 1,  /* the current item we're looking */
wrapper = document.getElementById("wrapper"),
transformVal = 0;
/* 1. Cloning last items and appending to first */  
for(var i=numberOfSlides ; i > 0 ; i--) {
clonedPre = items[items.length-i].cloneNode(true);
fragPre.append(clonedPre);
}
wrapper.insertBefore(fragPre , items[0]);
/* . Cloning first items and appending to first */  
for(var j = 0 ; j <= numberOfSlides-1 ; j++) {
clonedPost = items[j].cloneNode(true);
fragPost.append(clonedPost);
}
wrapper.appendChild(fragPost);
/* Slider arrow click function */  
var slideWidth=items[0].offsetWidth;
var counter = 0;
var timer = null;
var timeout = null;
wrapper.style.transform = "translate3d(" + (-slideWidth) * (numberOfSlides) + "px,0,0)";
function arrowClick(dir) {
// if timeout || timer is not null than sliding is processing right now, prevent processing user's actions in this case
if (timeout || timer) {
return;
}
timeout = setTimeout(function() {
counter = 0;
direction = dir;
var str = wrapper.style.transform;
var left = str.substring(12, str.length - 11);
console.log(left);
animateSlide(current, left);
timeout = null; // <-- setting timeout to null that will mean that function is partly (also will check timer) ready for new user's actions
}, 300);
}
/* slide number click function */  
function changeCurrent(curr) {
current = curr;
wrapper.style.transform =  "translate3d(" + -(slideWidth) * (current + (numberOfSlides-1)) + "px,0,0)";
}
/* actual sliding effect */  
function animateSlide(curr, left) {
// if timer is not prevent processing new animation
if (timer) {
return;
}
timer = setInterval(function() {
if(counter < slideWidth) {
counter += 2; // <-- this is the speed of animation. bigger number faster animating
transformVal = parseInt(left, 10) + (-(counter) * direction);
wrapper.style.transform = "translate3d(" + transformVal + "px,0,0)";
} else {
current += direction;
cycle = !!(current === 0 || current > len);
if (cycle) {
current = (current === 0)? len : 1;
wrapper.style.transform ="translate3d(" + (-(slideWidth) * (current + (numberOfSlides-1))) + "px,0,0)";
}
counter = 0;
clearInterval(timer);
timer = null; // <-- setting timer to null and now it's ready for another animaton
}
}, 0);  
}
body {
margin: 0;
padding: 0;
}
.carousel-slider-wrapper {
width: 1200px;
margin: 0 auto;
position: relative;
}
.slider-scroller-wrap {
overflow: hidden;
}
.slider-scroller {
font-size: 0;
white-space: nowrap;
position: relative;
top: 0;
margin: 0;
padding: 0;
}
.slider-scroller-inner {
/* transition: .2s ease-out; */

}
.slider-scroller-inner {
display: flex;
width: 100%;
position: relative;
}
.slider-scroller-inner .item {
display: inline-block;
vertical-align: top;
/* padding: 2px; */
box-sizing: border-box;
/* border: 1px solid; */
cursor: grab;
text-align: center;
flex: 0 0 33.33%;
}
.slider-scroller-inner .item img {
max-width: 100%;
}
button {
font: 40px "Courier New";
border: none;
box-shadow: 1px 2px 3px #666666;
background: #e4e4e4;
color: #626262;
cursor: pointer;
text-align: center;
position: absolute;
top: 50%;
transform: translateY(-50%);
height: 70px;
z-index: 1;
}
button.prev {
left: 0;
}
button.next {
right: 0;
}
label, a {
font: 14px Georgia;
font-style: italic;
color: #626262;
}
#indicators {
padding: 0;
margin: 1rem 0;
overflow: hidden;
text-align: center;
}
#indicators li {
padding: .5rem;
border-radius: 100%;
font-weight: bold;
background: #7592bd;
display: inline-flex;
height: 1.4rem;
width: 1.4rem;
color: #FFFFFF;
text-align: center;
cursor: pointer;
justify-content: center;
align-items: center;
margin-right: .3rem;
}
#indicators li:hover {
box-shadow: 1px 2px 3px #333333;
}
<div class="carousel-slider-wrapper">
<button class="prev" type="button" id="prev" onclick="arrowClick(-1)">&lsaquo;</button>
<div class="slider-scroller-wrap">
<div class="slider-scroller" id="gallery"> <!-- mask -->            
<div class="slider-scroller-inner" id="wrapper"> 
<div class="item"><img src="https://newyse-res.cloudinary.com/image/upload///t_mcms_larger/f_auto/v1511188164/33-2426430.jpg"></div>
<div class="item"><img src="https://newyse-res.cloudinary.com/image/upload///t_mcms_larger/f_auto/v1511186177/33-2425761.jpg"></div>
<div class="item"><img src="https://newyse-res.cloudinary.com/image/upload///t_mcms_larger/f_auto/v1511186164/33-2425751.jpg"></div>
<div class="item"><img src="https://newyse-res.cloudinary.com/image/upload///t_mcms_larger/f_auto/v1511185761/33-2425646.jpg"></div>
<div class="item"><img src="https://newyse-res.cloudinary.com/image/upload///t_mcms_larger/f_auto/v1557227665/33-2893456.jpg"></div>
<div class="item"><img src="https://newyse-res.cloudinary.com/image/upload///t_mcms_larger/f_auto/v1511970254/33-2437550.jpg"></div>
</div>    
</div>  
</div>
<button  class="next" type="button" id="next" onclick="arrowClick(1)">&rsaquo;</button>
</div>
<ul id="indicators" class="">
<li onclick="changeCurrent(1)">1</li>
<li onclick="changeCurrent(2)">2</li>
<li onclick="changeCurrent(3)">3</li>
<li onclick="changeCurrent(4)">4</li>
<li onclick="changeCurrent(5)">5</li>
<li onclick="changeCurrent(6)">6</li>
</ul>

最新更新