Поскольку DOM не предлагает никакого способа различения между первым запущенным событием прокрутки и последующими, которые оказываются частью одного и того же прокручиваемого движения, мы вынуждены думать о косвенных методах различения между ними. *
Если вы быстро прокрутите любой конкретный элемент, событие прокрутки будет запускаться много раз подряд. Используя следующий код, мы можем получить представление о том, как часто это происходит:
$('#exampleDiv').bind('mousewheel', function () {
console.log(new Date().getTime());
});
Когда вы прокрутите этот div, вы получите вывод консоли, который выглядит следующим образом:
// Using mouse wheelbar
251327626600149
251327626600215
251327626600265
251327626600282
251327626600332
251327626600365
// Using touchpad
251327626626207
251327626626225
251327626626261
251327626626276
251327626626312
251327626626345
Глядя на этот вывод, кажется, что события mousescroll
обычно запускаются в пределах от 20 до 60 мс друг от друга. Чтобы быть в безопасности, мы возьмем верхний предел за 100 мс. Это очень информативно, потому что мы можем использовать его, чтобы различать прокручивающиеся события, которые являются частью одного и того же действия, и события, которые вероятно различны и преднамеренно инициированы пользователем.
То, что вы могли бы сделать здесь, - это создать глобально доступную переменную timestamp, обновляя ее каждый раз, когда происходит событие mousescroll
, независимо от того, успешно оно или нет. Примерно так:
var timeStamp = new Date().getTime();
$('#exampleDiv').bind('mousewheel', function (event) {
var timeNow = new Date().getTime();
// Need to prevent the default scrolling behavior
event.preventDefault();
// If the last mousescroll happened less that 100 ms ago, update
// timeStamp and do nothing
if (timeNow - timeStamp < 100) {
timeStamp = timeNow;
return;
} else {
timeStamp = timeNow;
scrollToSomeOtherDiv();
}
});
Это фактически игнорирует все mousescroll
события, которые запускаются после начального события, которое предшествовало им всем, но начинает работать снова после того, как пользователь сделал паузу в течение 100 мс.
Это решит вашу проблему, кроме случаев, когда ваша scrollToSomeOtherDiv()
функция задействует какую-то трудоемкую анимацию. Конечно, вы можете сделать глобальное логическое значение isAnimating
и проверить, истинно ли оно каждый раз, когда происходит событие mousescroll
(убедитесь, что оно было установлено в обратный вызов после завершения анимации).
Это бы сработало, за исключением того, что оно могло бы дать пользователю возможность испытать резкий звук. Тот, кто хочет быстро прокрутить две панели, скорее всего, не будет делать паузу между прокрутками даже после начала анимации. Приведенный выше код будет видеть все их mousescroll
события как часть одного и того же прокручиваемого движения и будет продолжать их игнорировать!
В этом случае вы можете просто использовать время анимации в качестве порога. Вы устанавливаете timeStamp после начала анимации, а затем игнорируете все события mousescroll
в течение этого периода времени. Я написал пример здесь: http://jsfiddle.net/Sg8JQ/
Соответствующий код здесь:
var lastAnimation = 0;
var animationTime = 1000; // in ms
var quietPeriod = 500; // in ms, time after animation to ignore mousescroll
function scrollThis(event, delta, deltaX, deltaY) {
var timeNow = new Date().getTime();
// change this to deltaX/deltaY depending on which
// scrolling dir you want to capture
deltaOfInterest = deltaY;
if (deltaOfInterest == 0) {
// Uncomment if you want to use deltaX
// event.preventDefault();
return;
}
// Cancel scroll if currently animating or within quiet period
if(timeNow - lastAnimation < quietPeriod + animationTime) {
event.preventDefault();
return;
}
if (deltaOfInterest < 0) {
if ($('.active').next('div').length) {
lastAnimation = timeNow;
$('.active').removeClass('active').next('div').addClass('active');
$('html,body').animate( {
scrollTop: $('.active').offset().top }, animationTime);
}
} else {
if ($('.active').prev('div').length) {
lastAnimation = timeNow;
$('.active').removeClass('active').prev('div').addClass('active');
$('html,body').animate( {
scrollTop: $('.active').offset().top }, animationTime);
}
}
}
// Note: mousewheel() is defined in the mousewheel plugin by Brandon Aaron
// You could do without it, but you'd need to adjust for firefox and webkit
// separately.
//
// You couldn't use $(document).scroll() because it doesn't allow you to
// preventDefault(), which I use here.
$(document).mousewheel(scrollThis);
Я также включил quietPeriod
, который превышает время анимации, в течение которого вы хотите продолжать игнорировать mousescroll
события. Вы можете установить его на 0, если хотите, чтобы прокрутка была «отзывчивой», как только анимация будет завершена.