Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
25
Help us understand the problem. What is going on with this article?
@YujiHatanaka

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.

25
Help us understand the problem. What is going on with this article?
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
YujiHatanaka
PHPerややインフラ寄り。
oceans
自社メディア レシピサイトNadiaの開発・運営をしています。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
25
Help us understand the problem. What is going on with this article?