简体   繁体   English

如果CustomEvent在元素上触发,则取消'Click'DOM事件

[英]Cancel 'Click' DOM event if CustomEvent fires on element

I'm building an app in Cordova and, as many apps have, I'm trying to implement long-press events that occur after holding down on an element. 我正在Cordova构建一个应用程序,并且,正如许多应用程序所拥有的那样,我正在尝试实现在按住元素之后发生的长按事件。

I'm using https://github.com/john-doherty/long-press-event which fires a CustomEvent called 'long-press' after holding down on an element for 1.5 seconds. 我正在使用https://github.com/john-doherty/long-press-event ,在按住元素1.5秒后触发一个名为'long-press'的CustomEvent。

I have an element I'd like to put both a 'Click' listener and a 'long-press' listener on, similar to many mobile apps such as photo galleries or email that react differently between a click and a long-press event. 我有一个元素,我想把“点击”听众和“长按”听众,类似于许多移动应用程序,如照片画廊或电子邮件,在点击和长按事件之间做出不同反应。

The long-press event does fire, but the 'Click' event also fires every time and I can't find how or when I should try to stop it from firing. 长按事件确实会触发,但“点击”事件每次都会触发,我无法找到我应该如何或何时尝试阻止其发射。 I've tried several placements of stopDefault() and stopPropogation() to no avail. 我已经尝试了几个stopDefault()stopPropogation()无济于事。

The HTML with a listener is 带有监听器的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>

while the JS code is listening for a click on a lightbox-img, or a long-press on a portfolio image 而JS代码正在监听灯箱img上的点击,或者长时间按投资组合图像

$(document).on('long-press', '.portfolio-img', (e) => {
    e.preventDefault();
    e.stopPropagation();
    console.log('Portfolio long press event.');
 });
$(document).on('click', '.lightbox-img', imageClick);

Is there any actual way to fire the long-press event but have it cancel or stop the click event from occurring? 是否有任何实际的方法来解雇长按事件但是取消或停止发生点击事件?

One way to do this, is to disable the pointer-events from your clicked element from the moment your long-press event fired, and until the next mouseup event fires on the document. 实现此目的的一种方法是从您的long-press事件触发的那一刻起禁用所点击元素的pointer-events事件,直到下一个mouseup事件触发文档为止。

The best would probably to make it from your library, so here is a fork of this library which does now expose a preventDefaultClick() method on the CustomEvent: 最好的可能是从你的库中创建它,所以这里是这个库的一个分支,它现在在CustomEvent上公开一个preventDefaultClick()方法:

 (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.log('clicked')); btn.addEventListener('long-press', e => { console.log('long-press'); e.preventDefaultClick(); // prevents the incoming 'click' event }); 
 <button data-long-press-delay="500" id="btn">click me</button> 

But if like me yo have a mouse that does fire a bunch of events at every swipe, then you might prefer this demo where the wheel etc timeout triggers have been disabled: 但是,如果像我一样,你有一个鼠标在每次滑动时都会触发一堆事件,那么你可能更喜欢这个演示,其中轮子等超时触发器被禁用:

 (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.log('clicked')); btn.addEventListener('long-press', e => { console.log('long-press'); e.preventDefaultClick(); // prevents the incoming 'click' event }); 
 <button data-long-press-delay="500" id="btn">click me</button> 

Propagation is not the problem here - it's the fact that a long click event and a regular click event are actually the same thing, so they both fire. 传播不是问题所在 - 事实上,长按事件和常规点击事件实际上是同一个事实,因此它们都会触发。 They're triggered because you do mouse down and then mouse up. 它们被触发是因为你按下了鼠标然后向上鼠标。 The fact that there's a longer wait between the 2 events does not stop the regular click from being fired. 事件是两个事件之间的等待时间更长并不能阻止常规点击被触发。

The simplest way to handle this would be to set a flag that indicates whether the long-click event has been triggered, like this... 处理此问题的最简单方法是设置一个标志,指示是否已触发长按事件,如下所示......

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.log('Portfolio long press event.');
});

$(document).on('click', '.lightbox-img', (e) => {
    if (!longClickTriggered) {
        imageClick();
    }
    longClickTriggered = false;
});

I commented these lines out... 我评论了这些线...

e.preventDefault();
e.stopPropagation();

because I believe they were only there in your attempt to stop the click event handler from firing. 因为我相信他们只是在你试图阻止点击事件处理程序被触发时。

You can use a boolean, along with mousedown and mouseup listeners 您可以使用布尔值,以及mousedownmouseup侦听器

 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.log('hold'); isHold = true; } function onEleClick() { console.log('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> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM