Я создаю приложение в Cordova и, как и многие другие приложения, пытаюсь реализовать события длительного нажатия, которые происходят после удержания элемента.
Я использую https://github.com/john-doherty/long-press-event, который запускает CustomEvent под названием «долгое нажатие» после удержания элемента в течение 1,5 секунд.
У меня есть элемент, на который я хотел бы поместить как прослушиватель «Click», так и прослушиватель «длительного нажатия», подобно многим мобильным приложениям, таким как фотогалереи или электронная почта, которые по-разному реагируют между щелчком и событием длительного нажатия.
Событие длительного нажатия действительно срабатывает, но событие «Click» также срабатывает каждый раз, и я не могу найти, как и когда я должен попытаться остановить его срабатывание. Я пробовал несколько мест размещения stopDefault()
и stopPropogation()
безрезультатно.
HTML со слушателем
<div class = "grid-col grid-col--1">
<div class = "grid-item bd bdrs-4 bdw-1 bdc-grey-400">
<img class = "portfolio-img lightbox-img" src = "https://glamsquad.sgp1.cdn.digitaloceanspaces.com/GlamSquad/artist/1/portfolio/2019-05-16-06-07-370bc89b7bfe9769740c1f68f7e103340a94aaaeaa5d6f139f841e3c022ad309de.png">
</div>
<div class = "grid-item bd bdrs-4 bdw-1 bdc-grey-400">
<img class = "portfolio-img lightbox-img" src = "https://glamsquad.sgp1.cdn.digitaloceanspaces.com/GlamSquad/artist/1/portfolio/2019-05-16-06-07-38d8d03cc6edef043d25e9099b883cd235c823a267ab03b9e740934f06c4f87e2f.png">
</div>
</div>
в то время как код JS прослушивает щелчок по лайтбоксу или долгое нажатие на изображение портфолио
$(document).on('long-press', '.portfolio-img', (e) => {
e.preventDefault();
e.stopPropagation();
console.info('Portfolio long press event.');
});
$(document).on('click', '.lightbox-img', imageClick);
Есть ли реальный способ запустить событие длительного нажатия, но отменить или остановить событие щелчка?
Проблема здесь не в распространении — дело в том, что событие длинного клика и обычное событие клика на самом деле являются одним и тем же, поэтому они оба срабатывают. Они срабатывают, потому что вы нажимаете кнопку мыши, а затем поднимаете ее. Тот факт, что между двумя событиями существует более длительное ожидание, не мешает срабатыванию обычного клика.
Самый простой способ справиться с этим - установить флаг, который указывает, было ли запущено событие длинного щелчка, например...
var longClickTriggered = false;
$(document).on('long-press', '.portfolio-img', (e) => {
longClickTriggered = true;
//e.preventDefault(); // these 2 lines are probably not needed now
//e.stopPropagation();
console.info('Portfolio long press event.');
});
$(document).on('click', '.lightbox-img', (e) => {
if (!longClickTriggered) {
imageClick();
}
longClickTriggered = false;
});
Я закомментировал эти строки...
e.preventDefault();
e.stopPropagation();
потому что я считаю, что они были там только в вашей попытке остановить срабатывание обработчика события клика.
Вы можете использовать логическое значение вместе с слушателями mousedown
и mouseup
var timeoutId = 0, isHold = false;
$('#ele').on('mousedown', function() {
timeoutId = setTimeout(onEleHold, 1000);
}).on('mouseup', function() {
if (!isHold) {
onEleClick();
}
isHold = false;
clearTimeout(timeoutId);
timeoutId = 0;
});
function onEleHold() {
console.info('hold');
isHold = true;
}
function onEleClick() {
console.info('click');
}
#ele {
background: black;
width: 100px;
height: 20px;
color: white;
cursor: pointer;
}
<script src = "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id = "ele">Click Here</div>
Один из способов сделать это — отключить pointer-events
из выбранного вами элемента с момента запуска вашего события long-press
и до тех пор, пока в документе не сработает следующее событие mouseup
.
Вероятно, лучше всего сделать это из вашей библиотеки, поэтому вот ответвление этой библиотеки, которое теперь предоставляет метод preventDefaultClick()
для CustomEvent:
(function (window, document) {
'use strict';
var timer = null;
// check if we're using a touch screen
var isTouch = (('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0));
// switch to touch events if using a touch screen
var mouseDown = isTouch ? 'touchstart' : 'mousedown';
var mouseOut = isTouch ? 'touchcancel' : 'mouseout';
var mouseUp = isTouch ? 'touchend' : 'mouseup';
var mouseMove = isTouch ? 'touchmove' : 'mousemove';
// wheel/scroll events
var mouseWheel = 'mousewheel';
var wheel = 'wheel';
var scrollEvent = 'scroll';
// patch CustomEvent to allow constructor creation (IE/Chrome)
if (typeof window.CustomEvent !== 'function') {
window.CustomEvent = function(event, params) {
params = params || { bubbles: false, cancelable: false, detail: undefined };
var evt = document.createEvent('CustomEvent');
evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
return evt;
};
window.CustomEvent.prototype = window.Event.prototype;
}
// listen to mousedown event on any child element of the body
document.addEventListener(mouseDown, function(e) {
var el = e.target;
// get delay from html attribute if it exists, otherwise default to 1500
var longPressDelayInMs = parseInt(el.getAttribute('data-long-press-delay') || '1500', 10);
// start the timer
timer = setTimeout(fireLongPressEvent.bind(el, e), longPressDelayInMs);
});
// clear the timeout if the user releases the mouse/touch
document.addEventListener(mouseUp, function() {
clearTimeout(timer);
});
// clear the timeout if the user leaves the element
document.addEventListener(mouseOut, function() {
clearTimeout(timer);
});
// clear if the mouse moves
document.addEventListener(mouseMove, function() {
clearTimeout(timer);
});
// clear if the Wheel event is fired in the element
document.addEventListener(mouseWheel, function() {
clearTimeout(timer);
});
// clear if the Scroll event is fired in the element
document.addEventListener(wheel, function() {
clearTimeout(timer);
});
// clear if the Scroll event is fired in the element
document.addEventListener(scrollEvent, function() {
clearTimeout(timer);
});
/**
* Fires the 'long-press' event on element
* @returns {void}
*/
function fireLongPressEvent() {
var evt = new CustomEvent('long-press', { bubbles: true, cancelable: true });
// Expose a method to prevent the incoming click event
var el = this;
evt.preventDefaultClick = function() {
// disable all pointer-events
el.style["pointer-events"] = "none";
// reenable at next mouseUp
document.addEventListener(mouseUp, e => {
el.style["pointer-events"] = "all";
}, {once: true});
};
// fire the long-press event
this.dispatchEvent(evt);
clearTimeout(timer);
}
}(window, document));
btn.addEventListener('click', e => console.info('clicked'));
btn.addEventListener('long-press', e => {
console.info('long-press');
e.preventDefaultClick(); // prevents the incoming 'click' event
});
<button data-long-press-delay = "500" id = "btn">click me</button>
Но если, как и я, у вас есть мышь, которая запускает кучу событий при каждом пролистывании, то вы можете предпочесть эту демонстрацию, где триггеры тайм-аута колеса и т. д. отключены:
(function (window, document) {
'use strict';
var timer = null;
// check if we're using a touch screen
var isTouch = (('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0));
// switch to touch events if using a touch screen
var mouseDown = isTouch ? 'touchstart' : 'mousedown';
var mouseOut = isTouch ? 'touchcancel' : 'mouseout';
var mouseUp = isTouch ? 'touchend' : 'mouseup';
var mouseMove = isTouch ? 'touchmove' : 'mousemove';
// wheel/scroll events
var mouseWheel = 'mousewheel';
var wheel = 'wheel';
var scrollEvent = 'scroll';
// patch CustomEvent to allow constructor creation (IE/Chrome)
if (typeof window.CustomEvent !== 'function') {
window.CustomEvent = function(event, params) {
params = params || { bubbles: false, cancelable: false, detail: undefined };
var evt = document.createEvent('CustomEvent');
evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
return evt;
};
window.CustomEvent.prototype = window.Event.prototype;
}
// listen to mousedown event on any child element of the body
document.addEventListener(mouseDown, function(e) {
var el = e.target;
// get delay from html attribute if it exists, otherwise default to 1500
var longPressDelayInMs = parseInt(el.getAttribute('data-long-press-delay') || '1500', 10);
// start the timer
timer = setTimeout(fireLongPressEvent.bind(el, e), longPressDelayInMs);
});
// clear the timeout if the user releases the mouse/touch
document.addEventListener(mouseUp, function() {
clearTimeout(timer);
});
// clear the timeout if the user leaves the element
document.addEventListener(mouseOut, function() {
clearTimeout(timer);
});
// clear if the mouse moves
document.addEventListener(mouseMove, function() {
// clearTimeout(timer);
});
// clear if the Wheel event is fired in the element
document.addEventListener(mouseWheel, function() {
// clearTimeout(timer);
});
// clear if the Scroll event is fired in the element
document.addEventListener(wheel, function() {
// clearTimeout(timer);
});
// clear if the Scroll event is fired in the element
document.addEventListener(scrollEvent, function() {
// clearTimeout(timer);
});
/**
* Fires the 'long-press' event on element
* @returns {void}
*/
function fireLongPressEvent() {
var evt = new CustomEvent('long-press', { bubbles: true, cancelable: true });
// Expose a method to prevent the incoming click event
var el = this;
evt.preventDefaultClick = function() {
// disable all pointer-events
el.style["pointer-events"] = "none";
// reenable at next mouseUp
document.addEventListener(mouseUp, e => {
el.style["pointer-events"] = "all";
}, {once: true});
};
// fire the long-press event
this.dispatchEvent(evt);
clearTimeout(timer);
}
}(window, document));
btn.addEventListener('click', e => console.info('clicked'));
btn.addEventListener('long-press', e => {
console.info('long-press');
e.preventDefaultClick(); // prevents the incoming 'click' event
});
<button data-long-press-delay = "500" id = "btn">click me</button>
Спасибо! Это работает с добавлением того, что функция доступна в e.originalEvent.preventDefaultClick();
@Musa, только если вы подключили прослушиватель с помощью jQuery. В моем фрагменте нет ни jQuery, ни originalEvent
на evt
.
вы правы, в чистом javascript он работает напрямую
Я думаю, что ответ @archer ниже работает. вы можете попытаться понять разницу во времени вызова щелчка, добавив журнал консоли в обе функции. Событие длительного нажатия будет иметь временную задержку.