编写一些拖放代码,我想在我的 mouseup 处理程序中取消单击事件。我认为防止默认应该可以解决问题,但是仍然会触发单击事件。
有没有办法做到这一点?
这不起作用:
<div id="test">test</div>
<script>
$("#test").mouseup (function (e) {
var a = 1;
e.preventDefault();
});
$("#test").click (function (e) {
var a = 2;
});
编写一些拖放代码,我想在我的 mouseup 处理程序中取消单击事件。我认为防止默认应该可以解决问题,但是仍然会触发单击事件。
有没有办法做到这一点?
这不起作用:
<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>
在button
触发 click 事件之前,周围的 click 事件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-tag 返回 false,并在拖动结束时将其删除。
由于 onDragEnd 或 onMouseUp 处理程序是在浏览器解释单击之前运行的,因此我们需要检查拖动结束的位置以及单击的链接等等。如果它在拖动的链接之外结束(我们拖动链接以使光标不再位于链接上),我们删除 onDragEnd 中的 onclick 处理程序;但是如果它在光标位于拖动链接上的位置结束(将启动单击),我们让 onclick-handler 自行删除。够复杂了吧?
不是完整的代码,只是为了向您展示这个想法:
// 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,然后进行 preventDefault、返回 false、stopPropagation 等。尽管 Chrome 已经具有所需的行为,但这在 Chrome 上不起作用。如果浏览器不是 Chrome,只需将其设置为拖动功能仅将 noclick 设置为 true。
您的点击处理程序仍会被触发,但至少它有办法知道它刚刚从拖动中返回并做出相应的行为。
由于它们是不同的事件,因此您无法onclick
从取消onmouseup
,如果您调用preventDefault
orcancelBubble
或其他任何方式,您将停止该onmouseup
事件的进一步处理。可以这么说,该onclick
事件仍在等待中,尚未被解雇。
您需要的是您自己的布尔标志,例如isDragging
. 您可以在拖动开始时将其设置为 true(例如,在 内onmousedown
,或其他)。
但是,如果您直接从 将其重置为 false ,则当您收到事件 ( )onmouseup
时将不再拖动,因为之前会触发。onclick
isDragging == false
onmouseup
onclick
所以你需要做的是使用一个短的超时时间(例如setTimeout(function() {isDragging = false;}, 50);
),所以当你的onclick
事件被触发时,isDragging
仍然会是true
,并且你的onclick
事件处理程序可以if(isDragging) return false;
在它做任何其他事情之前简单地拥有。
可能最简单的解决方案是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
如果您拥有另一个单击处理程序,则另一种(更安全)的解决方案是检查单击处理程序(您要阻止的处理程序)是否阻止了事件默认操作。
<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 声明了一个函数(你也可以在鼠标向上做同样的事情)来决定是否处理 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);
没有多次执行。在我看来,如果它是 onMouseClick 也会被多次调用。
你是怎么做的很简单,你给所有对象添加一个 addEventListener 并监听“mousedown”和“mouseup”事件。如果你的'mousedown'事件函数被调用,你会显示一个带有'style.position =“absolute”的DIV窗口,必须是透明的,并占据整个窗口。并将 Z-Order 设置为 9999999 之类的值。如果将 DIV 隐藏在“MouseLeave”处,则 Click 可能会引发。所以也听听创建的 DIV 它的 mousedown 并隐藏 div 也只是为了确定。然后,您要抑制的对象的“单击”事件将不会引发。在“mouseup”中,您再次隐藏您创建的 div。
此技巧仅用于编写带有 WebView2 对象的应用程序,您无法控制所显示的 html 网站,但将 javascript 注入其中。对于所有其他方面,如果您可以控制 html 源代码,只需在用于取消或不取消的对象的 mousedown 中设置一个 var,然后在“单击”事件中,您只需查看 var 做什么。
$(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;
});
希望这能解决您的问题。