39

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

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


これは機能しません:

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

16 に答える 16

45

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

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

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デモ

何が起こるのですか:

のクリック イベントがトリガーされる前に、バブリング フェーズではなくキャプチャ フェーズに登録されているためbutton、周囲のクリック イベントが発生します。div

その後、ハンドラーはそのイベントcaptureClickの伝播を停止し、ボタンclickのハンドラーが呼び出されるのを防ぎます。clickまさにあなたが欲しかったもの。その後、クリーンアップのために自身を削除します。

キャプチャとバブリング:

キャプチャ フェーズは DOM ルートからリーフまで呼び出され、バブリング フェーズはリーフからルートまで呼び出されます (イベント順序のすばらしい説明を参照)。

jQuery は常にバブリング フェーズにイベントを追加するため、ここで純粋な JS を使用してキャプチャ イベントを特にキャプチャ フェーズに追加する必要があります。

IE は IE9 で W3C のイベント キャプチャ モデルを導入したため、これは IE < 9 では機能しないことに注意してください。


現在のイベント API では、既に追加されている別のイベント ハンドラーの前に新しいイベント ハンドラーを DOM 要素に追加することはできません。優先順位パラメーターはなく、イベント リスナーのリストを変更するための安全なクロスブラウザー ソリューションもありません

于 2013-11-29T16:49:11.417 に答える
7

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

onMouseUp ハンドラーは preventDefault や stopEvent などを使用してリンクのクリックをキャンセルできないように見えるため、リンク自体をキャンセルする必要があります。これは、ドラッグの開始時に a-tag に 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);
  }
}

これにより、これをどのように達成できるかについてのアイデアが得られることを願っています。私が言ったように、これは完全な解決策ではなく、概念を説明するだけです。

于 2012-01-19T14:18:06.937 に答える
4

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

少し遅れましたが、他の人の助けになるかもしれません。「noclick」などの名前のグローバル変数を作成し、false に設定します。アイテムをドラッグするときは、noclick を true に設定します。クリック ハンドラーで、noclick が true の場合は false に設定してから、preventDefault、return false、stopPropagation などを設定します。ただし、Chrome には既に目的の動作があるため、これは Chrome では機能しません。ブラウザが Chrome でない場合にのみ、ドラッグ機能が noclick を true に設定するようにします。

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

于 2012-05-20T22:58:26.460 に答える
3

onclickこれらは異なるイベントであるため、からキャンセルすることはできません。またはonmouseupを呼び出すと、イベントがそれ以上処理されなくなります。イベントはまだ保留中であり、いわばまだ起動されていません。preventDefaultcancelBubbleonmouseuponclick

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

しかし、これを から直接 false にリセットすると、イベント ( )を受け取っonmouseupたときにドラッグしなくなります。onclickisDragging == falseonmouseuponclick

したがって、必要なことは短いタイムアウト (例: setTimeout(function() {isDragging = false;}, 50);) を使用することです。そのため、onclickイベントが発生したときisDraggingは のままtrueであり、onclickイベント ハンドラーは他の処理を行うif(isDragging) return false;前に単純に持つことができます。

于 2012-06-17T20:21:16.137 に答える
0

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

    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;
    };
于 2012-07-29T13:28:38.047 に答える
0

可能かもしれませんが、この種の evt 管理を jQuery で処理できるかどうかはわかりません。このコード例は、あなたの期待からかけ離れたものではなく、少なくとも方向性を示すものであってはなりません。

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);
于 2011-12-30T23:50:31.407 に答える
0
$(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 
}
于 2011-12-27T11:30:16.393 に答える
-1

クリック イベントを抑制したい場合は、ステートメントevent.preventDefault()をクリック イベント ハンドラにのみ追加し、マウスアップ イベント ハンドラには追加しません。以下のコードを使用すると、機能します。

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

});
$("#test").click (function (e) {
 e.preventDefault();
  var a = 2;
});

これで問題が解決することを願っています。

于 2011-12-28T07:47:16.770 に答える
-1
$(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");
    });
于 2011-12-27T10:54:47.997 に答える