LoginSignup
2
2

More than 5 years have passed since last update.

jQuery Mobile Menu Pluginでreadイベントが2回実行される件

Last updated at Posted at 2015-01-07

問題点

このサイトを参考jQuery Mobile Menu Pluginを使って、スマホ用のドロワを実装してました。(横からペロって出てくるメニューですね)
あるページに、送信ボタンのクリックイベントをjQueryで実装したら、2回送信されていました。
原因を突き詰めると、どうやらjQuery Mobile Menu Pluginが悪いらしい。

githubのissuesにもあるように、readイベントが2回実行されるもよう。

対処

あまり宜しく無い実装ですが、イベントが登録されたかチェックして2回目のイベント登録を無視するようにしました。

<!DOCTYPE html>
<html>
  <head>
    <link href="/css/jquery.mobile-menu.css" rel="stylesheet">
    <link href="/css/style.css" rel="stylesheet">

    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
    <script src="/js/jquery.mobile-menu.js"></script>
  </head>
  <body>

    <nav class="navbar">
      <!-- start / drawer menu -->
      <div id="main-nav">
        <ul class="list-group">
          <li class="list-group-item">
            <a href="/">ホーム</a>
          </li>
          <li class="list-group-item">
            <a href="/login">ログイン</a>
          </li>
          <li class="list-group-item">
            <a href="/announce_list">お知らせ</a>
          </li>
        </ul>
      </div>
      <!-- end / drawer menu -->
    </nav>

    <form>
      <input type="text" name="name">
      <button id="do_send">送信</button>
    </form>


  <script type="text/javascript">
    $(function (){
      // Mobile Menuの設定
      $("body").mobile_menu({
        menu: ['#main-nav ul'],  //ドロワーメニュー内の内容
        menu_width: 200,  //メニューのサイズ
        prepend_button_to: '#mobile-bar',  //トグルとなるボタン
        button_content: '<i><</i>'  //ボタンの画像
      });

      //  #do_sendに登録されているクリックイベントの数が1以上なら強制return
      flg = hasDomEvent('do_send', 'click', 1);
      if (flg) { return; };

      // クリックイベントの登録
      $("#do_send").click(function(e){
        alert("クリックイベント発生!!");
        return false;
      });

    });


    /**
     *  指定したDOMのイベントの数が制限数以上かチェックする
     *    mobile-menu.jsのバグで2回readイベントが走って、同じ関数が2回登録されるのを防ぐ
     *
     *  @param  string  selector    セレクタ。調べたいDOMオブジェクトのセレクタ。現状idのみ可
     *  @param  string  eventName   イベント名。click,change等
     *  @param  int     limitLength 制限(最大)イベント数。DOMに許容されるイベント数
     *
     *  @return bool  検証結果。true:イベントがある,false:イベントが無い
     *  @example
     *    //  #do_sendに登録されているクリックイベントの数が1以上なら強制return
     *    flg = hasDomEvent('do_send', 'click', 1);
     *    if (flg) { return; };
     */
    function hasDomEvent(selector, eventName, limitLength) {
      var events = $._data(document.getElementById(selector), 'events');
      // console.log(events);
      if (events == null) { return false };
      var anyEvents = events[eventName];
      // console.log(anyEvents);
      var anyEventsLength = anyEvents.length;
      // console.log(anyEventsLength);
      var flg = (anyEventsLength > limitLength);
      // console.log(flg);

      return flg;
    }
  </script>
  </body>
</html>

まとめ

  • 登録イベントの数をチェック
  • イベントが登録されていたらreturn

そもそもプラグインで修正してくれればいいんですけどね。。。

追記:readイベントが実行された時に検証する

上の方法はあまり良くありませんでした。反省してます。
クリックイベントに限らず、readイベントに登録してあったajax処理が2回実行されて困りました。

以下修正版です。

   <script type="text/javascript">
    $(function (){
      // readイベントの回数を検証
      // 2回目以降なら終了
      if(!readEventValidateModul.getInstance().validate()){return;}
      // Mobile Menuの設定
      $("body").mobile_menu({
        menu: ['#main-nav ul'],  //ドロワーメニュー内の内容
        menu_width: 200,  //メニューのサイズ
        prepend_button_to: '#mobile-bar',  //トグルとなるボタン
        button_content: '<i><</i>'  //ボタンの画像
      });

      // クリックイベントの登録
      $("#do_send").click(function(e){
        alert("クリックイベント発生!!");
        return false;
      });

    });



    }
/**
 *  readイベントが実行された回数で検証するモジュール
 */
var readEventValidateModul;

readEventValidateModul = (function() {
  var count, increment, init, instance, isFirst, validate;
  count = 0;
  instance = null;
  init = function() {
    return {
      validate: validate
    };
  };
  increment = function() {
    count++;
  };
  isFirst = function() {
    return count === 0;
  };
  validate = function() {
    if (isFirst()) {
      increment();
      return true;
    }
    return false;
  };
  return {
    getInstance: function() {
      if (!instance) {
        instance = init();
      }
      return instance;
    }
  };
})();
  </script>

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2