ドラッグ&ドロップコードを記述して、マウスアップハンドラーのクリックイベントをキャンセルしたいと思います。デフォルトを防ぐことでうまくいくはずですが、クリックイベントはまだ発生します。
これを行う方法はありますか?
これは機能しません:
<div id="test">test</div>
<script>
$("#test").mouseup (function (e) {
var a = 1;
e.preventDefault();
});
$("#test").click (function (e) {
var a = 2;
});
同じ問題があり、解決策も見つかりませんでした。しかし、うまくいくように見えるハックを思いつきました。
OnMouseUpハンドラーはpreventDefaultやstopEventなどでリンクのクリックをキャンセルできないようなので、リンク自体をキャンセルする必要があります。これは、ドラッグの開始時にaタグにfalseを返すonclick属性を記述し、ドラッグの終了時にそれを削除することで実行できます。
また、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);
}
}
これがどのようにして達成できるかについての考えがあなたに与えられることを願っています。前述のとおり、これは完全な解決策ではなく、概念を説明するだけです。
クリックイベントをキャンセルする要素の周りに要素を配置し、それにキャプチャイベントハンドラーを追加します。
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
でクリックイベントがトリガーされる前に、周囲のdiv
でクリックイベントが発生します。これは、バブリングフェーズではなくキャプチャフェーズに自身を登録したためです。
次に、captureClick
ハンドラーはそのclick
イベントの伝播を停止し、ボタンのclick
ハンドラーが呼び出されないようにします。まさにあなたが欲しかったもの。その後、自分自身を削除してクリーンアップします。
キャプチャフェーズはDOMルートからリーフまで呼び出され、バブリングフェーズはリーフからルートまで呼び出されます(参照: イベントの順序のすばらしい説明 )。
jQueryは常にイベントをバブリングフェーズに追加するため、ここで純粋なJSを使用して、キャプチャイベントをキャプチャフェーズに追加する必要があります。
IEはIE9でW3Cのイベントキャプチャモデルを導入したため、これはIE <9.では機能しません。
現在のイベントAPIでは、すでに追加されている別のイベントハンドラの前に、新しいイベントハンドラをDOM要素に追加することはできません。優先度パラメータはなく、 イベントリスナーのリストを変更するための安全なクロスブラウザソリューションはありません 。
解決策があります!
このアプローチは私にとっては非常にうまくいきます(少なくともクロムでは):
on mousedown
現在移動中の要素にクラスを追加し、mouseup
でクラスを削除します。
そのクラスが行うすべてはセットpointer-events:none
どういうわけかこれはそれを機能させ、クリックイベントは発生しません。
問題は要素があることです。クリックに応答する必要があります。また、ドラッグする必要があります。ただし、ドラッグされた場合、ドロップされたときにクリックをトリガーする必要はありません。
少し遅れますが、多分それは誰かを助けるでしょう。 「noclick」などのグローバル変数を作成し、falseに設定します。アイテムをドラッグするときは、noclickをtrueに設定します。クリックハンドラーで、noclickがtrueの場合は、falseに設定してからpreventDefault、return false、stopPropagationなどを設定します。これはChromeでは機能しませんが、Chromeはすでに望ましい振る舞いをしています。ブラウザがChromeでない場合にドラッグ機能がnoclickをtrueに設定するようにしてください。
クリックハンドラーは引き続き発生しますが、少なくともドラッグハンドラーから戻ったことがわかり、それに応じて動作する方法があります。
私の状況に最適な解決策は:
el.addEventListener('mousedown', (event) => {
clickTime = new Date()
})
el.addEventListener('click', (event) => {
if (new Date() - clickTime < 150) {
// do something
}
})
これにより、ユーザーはリリースに150ミリ秒かかります。150ミリ秒以上かかる場合、クリックではなく一時停止と見なされます。
これらは異なるイベントであるため、onclick
からonmouseup
をキャンセルすることはできません。preventDefault
またはcancelBubble
などを呼び出すと、onmouseup
イベントの処理が停止されます。 onclick
イベントはまだ保留中であり、いわば発生していません。
必要なのは、独自のブールフラグです。 isDragging
。ドラッグの開始時にこれをtrueに設定できます(たとえば、onmousedown
内など)。
ただし、これをonmouseup
から直接falseにリセットすると、onclick
がonmouseup
の前に発生するため、onclick
イベント(_isDragging == false
_)を受け取ったときにドラッグできなくなります。
したがって、必要なのは短いタイムアウト(setTimeout(function() {isDragging = false;}, 50);
など)を使用することです。そのため、onclick
イベントが発生しても、isDragging
はtrue
のままであり、onclick
イベントハンドラーはif(isDragging) return false;
それは他に何でもします。
可能かもしれませんが、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だけに変更する必要もありません。
OnClickの関数を宣言します
_function onMouseClick(event){
// do sth
}
_
OnClickイベントを処理するかどうかを決定するために、MouseDownの関数を宣言します(uはマウスアップでも同じことができます)。
_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の場合は複数回呼び出されるように思えます。