取消鼠标向上事件处理程序中的单击事件

Cancel click event in the mouseup event handler

本文关键字:单击 事件 程序 事件处理 鼠标 取消      更新时间:2023-09-26

编写一些拖放代码,我想取消鼠标向上处理程序中的单击事件。我认为防止默认值应该可以解决问题,但仍然触发了单击事件。

有没有办法做到这一点?


这不起作用:

<div id="test">test</div>
<script>
$("#test").mouseup (function (e) {
  var a = 1;
  e.preventDefault();
});
$("#test").click (function (e) {
  var a = 2;
});

使用事件捕获阶段

在要取消其单击事件的元素周围放置一个元素,并向其添加捕获事件处理程序。

var btnElm = document.querySelector('button');
btnElm.addEventListener('mouseup', function(e){
    console.log('mouseup');
    
    window.addEventListener(
        'click',
        captureClick,
        true // <-- This registeres this listener for the capture
             //     phase instead of the bubbling phase!
    ); 
});
btnElm.addEventListener('click', function(e){
    console.log('click');
});
function captureClick(e) {
    e.stopPropagation(); // Stop the click from being propagated.
    console.log('click captured');
    window.removeEventListener('click', captureClick, true); // cleanup
}
<button>Test capture click event</button>

JSFiddle Demo

发生什么:

在触发button上的单击事件之前,周围div上的单击事件将被触发,因为它将自身注册为捕获阶段而不是冒泡阶段。

然后,captureClick处理程序停止传播其click事件,并阻止调用按钮上的click处理程序。正是你想要的。然后,它会自行移除以进行清理。

捕获与冒泡:

捕获阶段是从 DOM 根到叶子调用的,而冒泡阶段是从叶子到根(参见:事件顺序的精彩解释(。

jQuery总是将事件添加到冒泡阶段,这就是为什么我们需要在这里使用纯JS将我们的捕获事件专门添加到捕获阶段。

请记住,IE 在 IE9 中引入了 W3C 的事件捕获模型,因此这不适用于 IE <9。


使用当前事件 API,您无法在已添加另一个事件处理程序之前将新的事件处理程序添加到 DOM 元素。没有优先级参数,也没有安全的跨浏览器解决方案来修改事件侦听器列表。

有一个解决方案!

这种方法对我非常有效(至少在 chrome 中(:

mousedown我向

当前正在移动的元素添加一个类,并在mouseup删除该类。

该类所做的只是设置pointer-events:none

不知何故,这使它工作并且不会触发单击事件。

针对我的情况的最佳解决方案是:

let clickTime;
el.addEventListener('mousedown', (event) => {
  clickTime = new Date();
});
el.addEventListener('click', (event) => {
  if (new Date() - clickTime < 150) {
    // click
  } else {
    // pause
  }
});

这给了用户 150 毫秒的发布时间,如果他们花费的时间超过 150 毫秒,则被视为暂停,而不是点击

我遇到了同样的问题,也没有找到解决方案。但是我想出了一个似乎有效的黑客。

由于 onMouseUp 处理程序似乎无法取消对带有 preventDefault 或 stopEvent 或其他任何东西的链接的点击,我们需要使链接自行取消。这可以通过编写一个 onclick 属性来完成,该属性在拖动开始时向 a 标记返回 false,并在拖动结束时将其删除。

由于 onDragEnd 或 onMouseUp 处理程序是在浏览器解释单击之前运行的,因此我们需要做一些检查拖动结束的位置以及单击哪个链接等等。如果它在拖动的链接之外结束(我们拖动链接,以便光标不再在链接上(,我们删除 onDragEnd 中的 onclick 处理程序;但是,如果它结束于光标在拖动链接上的位置(将启动单击(,我们让 onclick 处理程序自行删除。够复杂了吧?

不是完整的代码,但只是为了向您展示这个想法:

// event handler that runs when the drag is initiated
function onDragStart (args) {
  // get the dragged element
  // do some checking if it's a link etc
  // store it in global var or smth
  // write the onclick handler to link element
  linkElement.writeAttribute('onclick', 'removeClickHandler(this); return false;');
}
// run from the onclick handler in the a-tag when the onMouseUp occurs on the link
function removeClickHandler (element) {
  // remove click handler from self
  element.writeAttribute('onclick', null);
}
// event handler that runs when the drag ends
function onDragEnds (args) {
  // get the target element
  // check that it's not the a-tag which we're dragging,
  // since we want the onclick handler to take care of that case
  if (targetElement !== linkElement) {
    // remove the onclick handler
    linkElement.writeAttribute('onclick', null);
  }
}

我希望这能让您了解如何实现这一目标。正如我所说,这不是一个完整的解决方案,只是解释了这个概念。

问题是有一个元素。它需要响应点击。它还需要拖动。但是,当它被拖动时,它不需要在放下时触发单击。

有点晚了,但也许它会帮助其他人。创建一个名为"noclick"或其他东西的全局变量并将其设置为 false。拖动项目时,将 noclick 设置为 true。在单击处理程序中,如果 noclick 为 true,请将其设置为 false,然后阻止默认值、返回 false、stopPropagation 等。不过,这在Chrome上不起作用,因为Chrome已经具有所需的行为。只需使拖动功能仅在浏览器不是 Chrome 时才将 noclick 设置为 true。

您的点击处理程序仍然会被触发,但至少它有办法知道它刚刚从拖动中返回并相应地运行。

由于它们是不同的事件,因此您无法从onmouseup取消onclick,如果您调用preventDefaultcancelBubble,或者其他什么,您将阻止进一步处理onmouseup事件。 可以这么说,onclick事件仍在悬而未决,尚未被解雇。

您需要的是您自己的布尔标志,例如 isDragging . 您可以在拖动开始时将其设置为 true(例如,在 onmousedown 内或其他任何内容(。

但是,如果您直接从 onmouseup 将其重置为 false,则当您收到onclick事件 ( isDragging == false 时,您将不会再拖动任何内容,因为onmouseuponclick之前触发。

因此,您需要做的是使用较短的超时(例如 setTimeout(function() {isDragging = false;}, 50); (,因此当触发onclick事件时,isDragging仍将true,并且您的onclick事件处理程序可以在执行任何其他操作之前具有if(isDragging) return false;

选项 #1:

可能最简单的解决方案是 Event.stopImmediatePropagation() .虽然这附带了一个警告,即同一元素上的所有其他点击事件侦听器在调用时将被取消,但在这种特定情况下,它会起作用。

<div id="test">test</div>
<script>
$("#test").mouseup (function (e) {
  var a = 1;
});
$("#test").click (function (e) {
  // You should add a check here to only stop
  // if the element was actually moved
  e.stopImmediatePropagation();
});
$("#test").click (function (e) {
  var a = 2;
});

例如,请参阅此代码笔:
https://codepen.io/guidobouman/pen/bGWeBmZ

选项#2:

如果您拥有其他点击处理程序,则另一种(更安全(的解决方案是在阻止事件默认操作时签入点击处理程序(您要阻止的那个(。

<div id="test">test</div>
<script>
$("#test").mouseup (function (e) {
  var a = 1;
});
$("#test").click (function (e) {
  // You should add a check here to only prevent
  // if the element was actually moved
  e.preventDefault();
});
$("#test").click (function (e) {
  if(e.defaultPrevented) {
    return;
  }
  var a = 2;
});
$(document).mouseup(function(event){
    event.preventDefault(); // this prevents only a default action but previously assigned listeners will be called
    event.stopImmediatePropagation() // if there are  others listeners which that shouldn't call 
}

这可能是可能的,但我不确定你是否可以用jQuery处理这种evt管理。这个代码示例应该离你的期望不远,或者至少给你一个方向。

function AddEvent(id, evt_type, ma_fonction, phase) {
    var oElt = document.getElementById(id);
    // modèle W3C mode bubbling
    if( oElt.addEventListener ) {
        oElt.addEventListener(evt_type, ma_fonction, phase);
    // modèle MSIE
    } else if( oElt.attachEvent ) {
        oElt.attachEvent('on'+evt_type, ma_fonction);
    }
    return false;
}
function DelEvent(id, evt_type, ma_fonction, phase) {
    var oElt = document.getElementById(id);
    // modèle W3C mode bubbling
    if( oElt.removeEventListener ) {
        oElt.removeEventListener(evt_type, ma_fonction, phase);
    // modèle MSIE
    } else if( oElt.detachEvent ) {
        oElt.detachEvent('on'+evt_type, ma_fonction);
    }
    return false;
}
    var mon_id = 'test';
    var le_type_evt = "mouseup";
    var flux_evt = false; // prevent bubbling
    var action_du_gestionnaire = function(e) {
        alert('evt mouseup on tag <div>');
        // 1ère méthode : DOM Lev 2
        // W3C
            if ( e.target )
                e.target.removeEventListener(le_type_evt, arguments.callee, flux_evt);
        // MSIE
            else if ( e.srcElement )
                e.srcElement.detachEvent('on'+le_type_evt, arguments.callee);
        // 2ème méthode DOM Lev2
        // DelEvent(mon_id, le_type_evt, action_du_gestionnaire, flux_evt);
    };

    AddEvent(mon_id, le_type_evt, action_du_gestionnaire, flux_evt);

我最近遇到了同样的问题。这是我的解决方案:)

    initDrag: function (element) {
        var moved = false,
            target = null;
        function move(e) {
            // your move code
            moved = true;
        };
        function end(e) {
            var e = e || window.event,
                current_target = e.target || e.srcElement;
            document.onmousemove = null;
            document.onmouseup = null;
            // click happens only if mousedown and mouseup has same target
            if (moved && target === current_target) 
                element.onclick = click;
            moved = false;
        };
        function click(e) {
            var e = e || window.event;
            e.preventDefault();
            e.stopPropagation();
            // this event should work only once
            element.onclick = null;
        };
        function init(e) {
            var e = e || window.event;
            target = e.target || e.srcElement;
            e.preventDefault();
            document.onmousemove = move;
            document.onmouseup = end;
        };
        element.onmousedown = init;
    };

这是我拖动并单击同一元素的解决方案。

$('selector').on('mousedown',function(){
  setTimeout(function(ele){ele.data('drag',true)},100,$(this));
}).on('mouseup',function(){
  setTimeout(function(ele){ele.data('drag',false)},100,$(this));
}).on('click',function(){
  if($(this).data('drag')){return;}
  // put your code here
});

我使用的解决方案如下:

var disable_click = false;
function click_function(event){
    if (!disable_click){
        // your code
    }
}
function mouse_down_function(event){
    disable_click = false; // will enable the click everytime you click
    // your code
}
function mouse_up_function(event){
    // your code
}
function mouse_drag_function(event){
    disable_click = true; // this will disable the click only when dragging after clicking
   // your code
}

根据名称将每个函数附加到相应的事件!

我的解决方案不需要全局变量或超时或更改 html 元素,只需 jquery 在普通 js 中肯定有一些含水价。

我为 onClick 声明了一个函数

function onMouseClick(event){
     // do sth
}

我为 MouseDown 声明了一个函数(u 也可以在鼠标向上时做同样的事情(来决定是否处理 onclick 事件

function onMouseDown(event){
     // some code to decide if I want a click to occur after mouseup or not
    if(myDecision){
        $('#domElement').on("click", onMouseClick);
    }
    else $('#domElement').off("click");
} 

快速说明:您应该确保
$('#domElement').on("click", onMouseClick);不会多次执行。在我看来,如果是鼠标点击也会被多次调用。

$(document).mouseup(function(event){ // make sure to set the event parameter
    event.preventDefault(); // prevent default, like you said
});

需要注意的重要事项是event参数。

编辑:你想取消拖拽吗?

我知道这样做的方法是使用 bind()(对于较旧的 jQuery 版本(或on()(对于 jQuery 1.7+(来附加 mousedown 事件,然后分别使用 unbind()off() 来分离它。

$(document)
    .on("mousedown", function(){...})
    .on("mouseup", function(){
        $(document).off("mousedown");
    });

如果您希望抑制单击事件,则可以仅在单击事件处理程序中添加语句 event.preventDefault((,而不是在 mouseup 事件处理程序中添加语句。使用以下代码,您将使其正常工作。

<div id="test">test</div>
<script>
$("#test").mouseup (function (e) {
  var a = 1;
});
$("#test").click (function (e) {
 e.preventDefault();
  var a = 2;
});

希望这能解决您的问题。

怎么做非常简单,你添加一个addEventListener到所有对象,并侦听'mousedown'和'mouseup'事件。如果调用了"mousedown"事件函数,则会显示一个DIV窗口,其中'style.position ="绝对",必须是透明的,并且占用整个窗口。并将 Z 顺序设置为 9999999 类似的东西。如果您在"鼠标离开"处隐藏 DIV,则可能会引发点击。因此,请听创建的DIV鼠标向下,并隐藏div以确保。然后,不会引发要抑制的对象的"单击"事件。在"鼠标向上"中,您再次隐藏您创建的div。

此提示仅用于编写具有 WebView2 对象的应用程序,在该对象中,您无法控制显示的 html 网站,而是向其注入 javascript。对于其他所有内容,如果您可以控制 html 源代码,只需在鼠标悬停中设置一个用于取消或不取消对象的变量,然后在"单击"事件中,您只需查看 var 该怎么做。