Help us understand the problem. What is going on with this article?

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

More than 3 years have 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.

YujiHatanaka
PHPerややインフラ寄り。
https://oceans-nadia.com
oceans
自社メディア レシピサイトNadiaの開発・運営をしています。
https://www.oceans-corp.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした