JavaScript
iscroll.js

iScroll.js と drawer.js のハンバーガーメニューがAndroidで動かない

More than 1 year has passed since last update.


概要

drawer.jsを使った、スマホ用バーガーメニュー実装で、新しいAndroidのChromeにおいて長いメニューがスクロールしない症状がありました。スクロールは、全くしない訳では無く、フリックで素早く動かすと若干スクロールするものの、通常のタップ移動では指を離したタイミングでメニューが閉じてしまいます。この不具合の修正を試みました。


詳細

Androidでは、2016年末頃からスクロール動作を滑らかにするために、addEventListenerにイベントを登録する際、デフォルトでそのイベント内部の preventDefault を実行しないモードになりました。

jQuery の on() でイベントを登録している場合、addEventListener の第3引数に {passive: false} を加えられるようなオプションは無いため、drawer.js内部で on()を使用している箇所をaddEventListener を使って書き直す必要があります。加えて何かとバグの多いiscroll.js ではAndroidのタッチ動作をうまく検出出来ていない様子なので、スマホだけに表示させる画面、という前提で動作するよう修正試みました。


修正ポイント


drawer.js(v3.2.2)


19行目

iScroll.js のデフォルトオプションを定義している部分。preventDefaultが基本ONになるようにしている。

修正前


drawer.js

          preventDefault: false


修正後


drawer.js

          preventDefault: true,



107行目

修正前


drawer.js

      if (touches) { 

$this.on('touchmove.' + namespace, function disableTouch(event) {
event.preventDefault();
});
}

修正後


drawer.js

      if (touches) {

document.addEventListener('touchmove.' + namespace, function disableTouch(event) {
event.preventDefault();
}, {passive: false});
}


iscroll.js(v5.2.0)


42行目

内部でaddEventListnerを addEventとしてエイリアスを作っている部分があるので、ここで Android対応の書き方にする。

修正前


iscroll.js

    me.addEvent = function (el, type, fn, capture) { 

el.addEventListener(type, fn, !!capture);
};

修正後


iscroll.js

    me.addEvent = function (el, type, fn, capture) {

el.addEventListener(type, fn, {passive: false});
};


191行目

マウスポインタの場合の処理だが、スマホのみで使う前提なので、タッチイベントと同じものとして扱わせる。

修正前


iscroll.js

        pointerdown: 3,

pointermove: 3,
pointerup: 3,

修正後


iscroll.js

        pointerdown: 1,

pointermove: 1,
pointerup: 1,


331行目

ポインター、マウスなどをdisableにする処理だが、条件分岐がAndroidの場合、望んだとおりにならないようなので、タッチデバイスしか扱わないのとChromeのデバッグ環境でも動くことを考えて修正。

修正前


iscroll.js

        disablePointer : !utils.hasPointer,

disableTouch : utils.hasPointer || !utils.hasTouch,
disableMouse : utils.hasPointer || utils.hasTouch,

修正後


iscroll.js

        disablePointer : false,

disableTouch : false,
disableMouse : false,


482行目、622行目

e.preventDefault();をコメントアウト

これは

IScroll.prototype = {の中の

_start: と

_end: のpreventDefault を無効にしている。

以上で Android と iPhoneで正常動作するようになった。


参考

この問題が起きているときに、Chromeブラウザのデバッグコンソールに以下のメッセージがでます。

Unable to preventDefault inside passive event listener due to target being treated as passive.