【移動端debug-3】部分アンドロイド型touchendイベントをトリガーしないソリューション

5221 ワード

最近、プロジェクトで奇妙な問題に遭遇しました.ページにボタンがあり、ページをスクロールするときに消え、スクロールを停止するときに表示させる必要があります.
一般的な考え方:
Step 1、touchstartイベントを傍受し、TouchオブジェクトのpageY初期値startYを記録する.
Step 2、touchmoveイベントを傍受し、TouchオブジェクトにおけるpageYの変化後の値endYを記録し、(endY-startY)より大きい絶対値がある閾値より大きい場合はボタンを隠す.
Step 3、touchendイベントを傍受し、touchendをトリガするとボタンを表示する
コードは次のとおりです.
var startY,endY;

$("body").on("touchstart", touchStartRecord)
             .on("touchmove", touchMoveHide)
            .on("touchend", touchEndShow);
function touchStartRecord(event){ var touch = event.touches[0]; startY = touch.pageY; }; function touchMoveHide(event){ var touch = event.touches[0]; endY = touch.pageY; if (Math.abs(endY - startY) >= 5) { // } }; function touchEndShow(event){ // };

私たちは考えがはっきりしていて簡潔で、iPhoneで私たちの効果を順調に実現することができますが、ニマはアンドロイドに着いて、指がスクリーンを離れた後、ボタンが現れませんでした!!!WTF!
ツールでデバッグして、touchendイベントをトリガーする関数の中で点を中断して、意外にも入ることができません!!!
この問題の原因はtouchendイベントがトリガーされていないことです!
 
どのように解決しますか?
stackoverflowではすでに話題の議論があり、多くの人がこの問題について長い間、グーグルにバグを提起していた(Google転送ゲート:WebView touchevents are not fired propperly if e.preventDefault()is not used on touchstart and touchmove)が、最新のアンドロイドバージョンはまだ修復されていない......再びWTF!!
ディスカッションでは、次の2つのソリューションについて説明します.
ソリューション1:
touchstartまたはtouchmoveイベントを傍受する関数で、イベントのデフォルトの動作eventを阻止します.preventDefault()ではtouchendで正常にトリガーされます.
コードは次のとおりです.
var startY,endY;

$("body").on("touchstart", touchStartRecord)
             .on("touchmove", touchMoveHide)
            .on("touchend", touchEndShow);

function touchStartRecord(event){
        var touch = event.touches[0];
         startY = touch.pageY;
 };

function touchMoveHide(event){
        var touch = event.touches[0];
        endY = touch.pageY; 
          if (Math.abs(endY - startY) >= 5) {
            //           
 event.preventDefault();
         }
 };

function touchEndShow(event){
          //             
 };

ニマ、転がれないでしょう......モバイル端末touchmoveイベントのデフォルトの動作はページをスクロールすることですので、私たちは止めました.touchendはトリガーですが、私たちが望んでいる効果ではありません.3度目のWTF!!!
海外の有名なプラグインmobiscrollのブログでは、この問題に関するいくつかの処理経験を共有しています.(転送ゲート:Working with touch events)
On Android ICS if no  preventDefault  is called on  touchstart  or the first  touchmove , further touchmove  events and the  touchend  will not be fired. As a workaround we need to decide in the first  touchmove  if this is a scroll (so we don’t call  preventDefault ) and then manually trigger  touchend。
Android 4.0システム(Android ICSシステム)では、touchstartと最初のtouchmoveがトリガーされた場合、preventDefault, touchmove( ) touchend 。 touchmove ( , preventDefault ) touchend。は呼び出されません.
 
ソリューション2:
touchcancelとtouchendイベントを同時にバインドすることで、アンドロイド上でtouchcancelをトリガーすることでボタンを再表示できます.
touchcancelでは正常にトリガーされますが、私たちのこのニーズの中で、touchcancelの場合、私たちもボタンを再表示したいと思っています.それはちょうど私たちが望んでいる効果ではありませんか.
コードは次のとおりです.
var startY,endY;

$("body").on("touchstart", touchStartRecord)
             .on("touchmove", touchMoveHide)
            .on("touchcancel touchend", touchEndShow);

function touchStartRecord(event){
        var touch = event.touches[0];
         startY = touch.pageY;
 };

function touchMoveHide(event){
        var touch = event.touches[0];
        endY = touch.pageY; 
          if (Math.abs(endY - startY) >= 5) {
            //           
         }
 };

function touchEndShow(event){
          //             
 };

はい、今は私たちのニーズを解決することができますが、実際には最適解ではありません.touchcancelに単独で操作を追加したいなら、できませんから.だから最も根本的なのはやはりグーグルができるだけ早くこの歴史の残したバグを解決することを望んでいます.