12

ボタンのクリックを処理しようとしています。「ボタン」は、子も含めることができるカスタム div です。クリック コールバックは、ユーザーが要素内でクリックとリリースの両方を行ったときに発生する必要があります。ユーザーが内側をクリックしてからドラッグして外側に放した場合、ハンドラーは起動しません。デスクトップとモバイルの両方でこれを機能させる必要があるため、イベントを使用mousedown/mouseupしてtouchstart/touchendいます。

ユーザーが外部でリリースした場合でも、ボタン クラスを「押された」から「通常」に変更する必要があるため、ドキュメント上でリリース イベントをキャプチャするリスナーを追加する必要があります。

    var $myElement = $("#myelement"); //This is a div and can also contain children.

    $myElement.on("mousedown touchstart", function(e){  

        $(this).addClass("pressed");    

        $(document).on("mouseup touchend", function listener(e){
            $myElement.removeClass("pressed");

            $(document).off("mouseup touchend", listener);

            var $target = $(e.target);
            if ($target.is($myElement) || $target.parents().is($myElement)){        
                //FIXME
                alert("Inside!");

                //do something here
                return false;
            } else {
                //FIXME
                alert("Outside!");

                //let event bubble
            }
        });

        return false;
    });

クリックでは問題なく動作しますが、タッチ イベントでは期待どおりに動作しません。これを Chrome for Android でテストし、要素を押してからドラッグすると、「Inside!」アラートが表示されます。

問題は次の状態にあります。

if ($target.is($myElement) || $target.parents().is($myElement)){

touchendボタンまたは子のいずれかでイベントが発生したかどうかを確認しようとしています。ボタンに子がない場合、ボタンをクリックしてから離すと、OR 句の最初の部分が true に解決されます。ボタンに子があり、子をクリックし、画面の他の部分で離すと、句の 2 番目の部分が true になります。

このコードの何が問題になっていますか?

前もって感謝します。

更新
BlackBerry 10 でも同じ結果でテストしました。どうやら、イベントのターゲットtouchendはボタン (または子) です。外側をクリックした場合でもそうです。これはどのように機能するはずですか?

更新
そしてここに理由があります。これは、W3Cドキュメントがイベントについて言っていることです:

このイベントのターゲットは、タッチ ポイントがターゲット要素のインタラクティブ領域の外に移動した場合でも、このタッチ ポイントが表面に配置されたときに touchstart イベントを受け取ったものと同じ要素でなければなりません。

私には意味がありませんが、とにかくこれは私の問題を説明しています。touchend指が離された要素でイベントが呼び出されると想定していました。別のアプローチを使用して、指のリリースを外部で検出することは可能でしょうか?

UPDATEを使用して要素を取得するために
、の座標を取得しようとしました。問題は、このイベントに座標が含まれていないことです (およびリストが空です)。デバッガーでイベントを徹底的に調べましたが、元のイベント以外に座標を取得する方法はありません。次に、最後のイベントをキャッシュしてそこから座標を取得できると考えましたが、このイベントには独自の座標がありません! 役に立たないのに、一体なぜこの 2 つのイベントが存在するのでしょうか。そして、このアプローチを iOS、Android、BB10 でテストしましたが、同じ結果が得られました。toucheventdocument.elementFromPointchangedTouchestouchestouchmove

私は断念しました。ユーザーが外部をクリックした場合でも、コールバックを呼び出します。これが 2013 年のものだとは信じられませんが、これを行う (簡単な) 方法はありませんか? ドラッグ アンド ドロップ API を使用できましたが、これによれば、モバイルではサポートされていません (モバイル Web 開発が大好きです)。

4

2 に答える 2

10

最後に (ほぼ) BB10 と Android で動作するようになりました。質問の更新に問題の痕跡を残したので、要約すると、touchendイベントターゲットは と同じでありtouchstart、座標なしで発生します (API デザイナーは、何らかの理由でそれらをプロパティで「非表示」にすることにしましたoriginalEvent:) . そこで、 からタッチ終了座標をchangedTouches[0].pageX取得changedTouches[0].pageYし、 を使用して指が離された要素を取得していdocument.elementFromPointます。(このメソッドにイベント座標を供給する前に、x と y にスクロール オフセットを追加する必要があります)。次に、その時点の要素がボタン (またはその子) である場合、クリックを処理します。

    var $myElement = $("#myelement"); //This is a div and can also contain children.
    var startEvent = touchDevice() ?  "touchstart" : "mousedown";
    var releaseEvent = touchDevice() ?  "touchend" : "mouseup";

    $myElement.on(startEvent, function(e){  

        $(this).addClass("pressed");    

        $(document).on(releaseEvent, function listener(e){
            $myElement.removeClass("pressed");

            $(document).off(releaseEvent, listener);

            var $target = null;
            if(e.type === "mouseup"){
                 $target = $(e.target);         
            } else {            
                var x = e.originalEvent.changedTouches[0].pageX - window.pageXOffset;
                var y = e.originalEvent.changedTouches[0].pageY - window.pageYOffset;
                var target = document.elementFromPoint(x, y);

                if(target){
                    $target = $(target);
                }           
            }

            if ($target !== null && ($target.is($myElement) || $target.parents().is($myElement))){      
                //FIXME
                alert("Inside!");

                //callback here
                return false;
            } else {
                //FIXME
                alert("Outside!");
            }
        });

        return false;
    });

今、私は新しい問題を抱えています.iOSでは、何らかの形でクリックイベントが複製されています. しかし、これは別の質問に値します (まだ存在しない場合)。

于 2013-07-15T12:55:41.797 に答える
1

まとめて、別のよりきちんとしたアプローチが必要です。

デスクトップとモバイル デバイスにそれぞれ onmousemove と ontouchmove を実装します。

btn_obj.onmousemove = CancelOnClick (this);

CancelOnClick 関数を実装して、フラグを押された状態から通常状態に設定します。すべての要素とその子に基づく条件からあなたを救います。

それが役立つことを願っています。

于 2013-07-15T09:09:41.853 に答える