web-dev-qa-db-ja.com

mouseupイベントハンドラーでクリックイベントをキャンセルする

ドラッグ&ドロップコードを記述して、マウスアップハンドラーのクリックイベントをキャンセルしたいと思います。デフォルトを防ぐことでうまくいくはずですが、クリックイベントはまだ発生します。

これを行う方法はありますか?


これは機能しません:

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

同じ問題があり、解決策も見つかりませんでした。しかし、うまくいくように見えるハックを思いつきました。

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);
  }
}

これがどのようにして達成できるかについての考えがあなたに与えられることを願っています。前述のとおり、これは完全な解決策ではなく、概念を説明するだけです。

6

イベントキャプチャフェーズを使用する

クリックイベントをキャンセルする要素の周りに要素を配置し、それにキャプチャイベントハンドラーを追加します。

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要素に追加することはできません。優先度パラメータはなく、 イベントリスナーのリストを変更するための安全なクロスブラウザソリューションはありません

19
flu

解決策があります!

このアプローチは私にとっては非常にうまくいきます(少なくともクロムでは):

on mousedown現在移動中の要素にクラスを追加し、mouseupでクラスを削除します。

そのクラスが行うすべてはセットpointer-events:none

どういうわけかこれはそれを機能させ、クリックイベントは発生しません。

12
FDIM

問題は要素があることです。クリックに応答する必要があります。また、ドラッグする必要があります。ただし、ドラッグされた場合、ドロップされたときにクリックをトリガーする必要はありません。

少し遅れますが、多分それは誰かを助けるでしょう。 「noclick」などのグローバル変数を作成し、falseに設定します。アイテムをドラッグするときは、noclickをtrueに設定します。クリックハンドラーで、noclickがtrueの場合は、falseに設定してからpreventDefault、return false、stopPropagationなどを設定します。これはChromeでは機能しませんが、Chromeはすでに望ましい振る舞いをしています。ブラウザがChromeでない場合にドラッグ機能がnoclickをtrueに設定するようにしてください。

クリックハンドラーは引き続き発生しますが、少なくともドラッグハンドラーから戻ったことがわかり、それに応じて動作する方法があります。

4
Kaylakaze

私の状況に最適な解決策は:

el.addEventListener('mousedown', (event) => {
  clickTime = new Date()
})

el.addEventListener('click', (event) => {
  if (new Date() - clickTime < 150) {
    // do something
  }
})

これにより、ユーザーはリリースに150ミリ秒かかります。150ミリ秒以上かかる場合、クリックではなく一時停止と見なされます。

3
Kim T

これらは異なるイベントであるため、onclickからonmouseupをキャンセルすることはできません。preventDefaultまたはcancelBubbleなどを呼び出すと、onmouseupイベントの処理が停止されます。 onclickイベントはまだ保留中であり、いわば発生していません。

必要なのは、独自のブールフラグです。 isDragging。ドラッグの開始時にこれをtrueに設定できます(たとえば、onmousedown内など)。

ただし、これをonmouseupから直接falseにリセットすると、onclickonmouseupの前に発生するため、onclickイベント(_isDragging == false_)を受け取ったときにドラッグできなくなります。

したがって、必要なのは短いタイムアウト(setTimeout(function() {isDragging = false;}, 50);など)を使用することです。そのため、onclickイベントが発生しても、isDraggingtrueのままであり、onclickイベントハンドラーはif(isDragging) return false;それは他に何でもします。

1
Lee Kowalkowski

可能かもしれませんが、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);
0
hornetbzz

私は最近同じ問題に直面しました。これが私の解決策です:)

    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;
    };
0
starl1ng

これは、同じ要素をドラッグアンドクリックするための私のソリューションです。

$('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
});
0
Quyền Lê

私が使用するソリューションは次のとおりです:

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
}

名前に従って、各関数を適切なイベントにアタッチします。

0

私のソリューションは、グローバル変数やタイムアウトを必要とせず、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の場合は複数回呼び出されるように思えます。

0
Tom