防止自定义jQuery图像轮播中的事件重叠 [英] Prevent event overlap in custom jQuery image carousel
问题描述
更新:我在下面发布的解决方案还不够好,因为它使除了有效的 对点击不响应 以外的所有项目符号,而不是 排队 进行改进.
UPDATE: the solution I have posted below is not good enough, because it makes all the bullets except the active one non-responsive to clicks, instead of queueing them, so there is room for improvement.
我正在使用jQuery和CSS制作自定义图像轮播.我的目标是使它真正轻巧,但具有(仅)足够的功能:项目符号",自动前进,响应能力.
I am working on a custom image carousel, using jQuery and CSS. My aim is to make it really lightweight but with (just) enough features: "bullets", auto-advance, responsiveness.
工作正常,但我发现了一个无法修复的错误:当我快速连续单击2个项目符号时-这意味着在第二个项目符号触发的转换完成之前单击第二个项目符号-过渡以一种我无法描述的怪异方式重叠,但可以在下面看到:
It works fine, but I have discovered a bug I was unable to fix: when I click 2 bullets in rapid succession - which means clicking the second before the transition triggered by the first is finished - the transitions overlap in a weird manner I can not describe but is visible below:
var $elm = $('.slider'),
$slidesContainer = $elm.find('.slider-container'),
slides = $slidesContainer.children('a'),
slidesCount = slides.length,
slideHeight = $(slides[0]).find('img').outerHeight(false),
animationspeed = 1500,
animationInterval = 7000;
// Set (initial) z-index for each slide
var setZindex = function() {
for (var i = 0; i < slidesCount; i++) {
$(slides[i]).css('z-index', slidesCount - i);
}
};
setZindex();
var displayImageBeforeClick = null;
var setActiveSlide = function() {
$(slides).removeClass('active');
$(slides[activeIdx]).addClass('active');
};
var advanceFunc = function() {
if ($('.slider-nav li.activeSlide').index() + 1 != $('.slider-nav li').length) {
$('.slider-nav li.activeSlide').next().find('a').trigger('click');
} else {
$('.slider-nav li:first').find('a').trigger('click');
}
}
var autoAdvance = setInterval(advanceFunc, animationInterval);
//Set slide height
$(slides).css('height', slideHeight);
// Append bullets
if (slidesCount > 1) {
/* Prepend the slider navigation to the slider
if there are at least 2 slides */
$elm.prepend('<ul class="slider-nav"></ul>');
// make a bullet for each slide
for (var i = 0; i < slidesCount; i++) {
var bullets = '<li><a href="#">' + i + '</a></li>';
if (i == 0) {
// active bullet
var bullets = '<li class="activeSlide"><a href="#">' + i + '</a></li>';
// active slide
$(slides[0]).addClass('active');
}
$('.slider-nav').append(bullets);
}
};
var slideUpDown = function() {
// set top property for all the slides
$(slides).not(displayImageBeforeClick).css('top', slideHeight);
// then animate to the next slide
$(slides[activeIdx]).animate({
'top': 0
}, animationspeed);
$(displayImageBeforeClick).animate({
'top': "-100%"
}, animationspeed);
};
$('.slider-nav a').on('click', function(event) {
displayImageBeforeClick = $(".slider-container .active");
activeIdx = $(this).text();
if ($(slides[activeIdx]).hasClass("active")) {
return false;
}
$('.slider-nav a').closest('li').removeClass('activeSlide');
$(this).closest('li').addClass('activeSlide');
// Reset autoadvance if user clicks bullet
if (event.originalEvent !== undefined) {
clearInterval(autoAdvance);
autoAdvance = setInterval(advanceFunc, animationInterval);
}
setActiveSlide();
slideUpDown();
});
body * {
box-sizing: border-box;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
.slider {
width: 100%;
height: 300px;
position: relative;
overflow: hidden;
}
.slider .slider-nav {
text-align: center;
position: absolute;
padding: 0;
margin: 0;
left: 10px;
right: 10px;
bottom: 2px;
z-index: 30;
}
.slider .slider-nav li {
display: inline-block;
width: 20px;
height: 3px;
margin: 0 1px;
text-indent: -9999px;
overflow: hidden;
background-color: rgba(255, 255, 255, .5);
}
.slider .slider-nav a {
display: block;
height: 3px;
line-height: 3px;
}
.slider .slider-nav li.activeSlide {
background: #fff;
}
.slider .slider-nav li.activeSlide a {
display: none;
}
.slider .slider-container {
width: 100%;
text-align: center;
}
.slider .slider-container a {
display: block;
position: absolute;
top: 0;
left: 0;
right: 0;
}
.slider .slider-container img {
transform: translateX(-50%);
margin-left: 50%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div class="container">
<div class="slider slider-homepage">
<div class="slider-container">
<a href="#">
<img src="https://picsum.photos/1200/300/?gravity=east" alt="">
</a>
<a href="#">
<img src="https://picsum.photos/1200/300/?gravity=south" alt="">
</a>
<a href="#">
<img src="https://picsum.photos/1200/300/?gravity=west" alt="">
</a>
</div>
</div>
</div>
如何避免这种因缺乏更好用词而被称为事件拥挤(重叠)的现象?
How could I prevent this phenomenon I would call, for lack of a better term, an event crowding (overlap)?
推荐答案
您可以使用来链接动画. jQuery延迟对象和承诺.这是可让您轻松完成此课程的课程.
You can chain your animations using jQuery deferred object and Promise. Here is the class allowing you to do it easily.
var Queue = function() {
var lastPromise = null;
this.add = function(callable) {
var methodDeferred = $.Deferred();
var queueDeferred = this.setup();
// execute next queue method
queueDeferred.done(function() {
// call actual method and wrap output in deferred
callable().then(methodDeferred.resolve)
});
lastPromise = methodDeferred.promise();
};
this.setup = function() {
var queueDeferred = $.Deferred();
// when the previous method returns, resolve this one
$.when(lastPromise).always(function() {
queueDeferred.resolve();
});
return queueDeferred.promise();
}
};
摆弄着动画.
PS:我增加了按钮的大小以便更轻松地单击
PS: I increase the size of the buttons to click more easily
var $elm = $('.slider'),
$slidesContainer = $elm.find('.slider-container'),
slides = $slidesContainer.children('a'),
slidesCount = slides.length,
slideHeight = $(slides[0]).find('img').outerHeight(false),
animationspeed = 1500,
animationInterval = 7000;
// Set (initial) z-index for each slide
var setZindex = function() {
for (var i = 0; i < slidesCount; i++) {
$(slides[i]).css('z-index', slidesCount - i);
}
};
setZindex();
var setActiveSlide = function() {
$(slides).removeClass('active');
$(slides[activeIdx]).addClass('active');
};
var advanceFunc = function() {
if ($('.slider-nav li.activeSlide').index() + 1 != $('.slider-nav li').length) {
$('.slider-nav li.activeSlide').next().find('a').trigger('click');
} else {
$('.slider-nav li:first').find('a').trigger('click');
}
}
var autoAdvance = setInterval(advanceFunc, animationInterval);
//Set slide height
$(slides).css('height', slideHeight);
// Append bullets
if (slidesCount > 1) {
/* Prepend the slider navigation to the slider
if there are at least 2 slides */
$elm.prepend('<ul class="slider-nav"></ul>');
// make a bullet for each slide
for (var i = 0; i < slidesCount; i++) {
var bullets = '<li><a href="#">' + i + '</a></li>';
if (i == 0) {
// active bullet
var bullets = '<li class="activeSlide"><a href="#">' + i + '</a></li>';
// active slide
$(slides[0]).addClass('active');
}
$('.slider-nav').append(bullets);
}
};
var Queue = function() {
var lastPromise = null;
this.add = function(callable) {
var methodDeferred = $.Deferred();
var queueDeferred = this.setup();
// execute next queue method
queueDeferred.done(function() {
// call actual method and wrap output in deferred
callable().then(methodDeferred.resolve)
});
lastPromise = methodDeferred.promise();
};
this.setup = function() {
var queueDeferred = $.Deferred();
// when the previous method returns, resolve this one
$.when(lastPromise).always(function() {
queueDeferred.resolve();
});
return queueDeferred.promise();
}
};
var queue = new Queue();
var slideUpDown = function(previousIdx, activeIdx) {
queue.add(function() {
return new Promise(function(resolve, reject) {
// set top property for all the slides
$(slides).not(slides[previousIdx]).css('top', slideHeight);
// then animate to the next slide
$(slides[activeIdx]).animate({
'top': 0
}, animationspeed);
$(slides[previousIdx]).animate({
'top': "-100%"
}, animationspeed, 'swing', resolve);
})
})
};
var previousIdx = '0' // First slide
$('.slider-nav a').on('click', function(event) {
activeIdx = $(this).text();
// Disable clicling on an active item
if ($(slides[activeIdx]).hasClass("active")) {
return false;
}
$('.slider-nav a').closest('li').removeClass('activeSlide');
$(this).closest('li').addClass('activeSlide');
// Reset autoadvance if user clicks bullet
if (event.originalEvent !== undefined) {
clearInterval(autoAdvance);
autoAdvance = setInterval(advanceFunc, animationInterval);
}
setActiveSlide();
slideUpDown(previousIdx, activeIdx);
previousIdx = activeIdx
});
body * {
box-sizing: border-box;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
.slider {
width: 100%;
height: 300px;
position: relative;
overflow: hidden;
}
.slider .slider-nav {
text-align: center;
position: absolute;
padding: 0;
margin: 0;
left: 10px;
right: 10px;
bottom: 2px;
z-index: 30;
}
.slider .slider-nav li {
display: inline-block;
width: 20px;
height: 6px;
margin: 0 1px;
text-indent: -9999px;
overflow: hidden;
background-color: rgba(255, 255, 255, .5);
}
.slider .slider-nav a {
display: block;
height: 6px;
line-height: 3px;
}
.slider .slider-nav li.activeSlide {
background: #fff;
}
.slider .slider-nav li.activeSlide a {
display: none;
}
.slider .slider-container {
width: 100%;
text-align: center;
}
.slider .slider-container a {
display: block;
position: absolute;
top: 0;
left: 0;
right: 0;
}
.slider .slider-container img {
transform: translateX(-50%);
margin-left: 50%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div class="container">
<div class="slider slider-homepage">
<div class="slider-container">
<a href="#">
<img src="https://picsum.photos/1200/300/?gravity=east" alt="">
</a>
<a href="#">
<img src="https://picsum.photos/1200/300/?gravity=south" alt="">
</a>
<a href="#">
<img src="https://picsum.photos/1200/300/?gravity=west" alt="">
</a>
</div>
</div>
</div>
这篇关于防止自定义jQuery图像轮播中的事件重叠的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!