jQueryのカスタムイベントはどこにバインドさせるべきか
例えばサイドバーのアニメーションを促すカスタムイベントを使う場合。
サイドバーにはいろんな機能があるとして、専門のサイドバーオブジェクトを作ったとする。
でも $('#sidebar').on('click', function() { /* */ }) とすると保守がしんどい。
この場合、$('#sidebar').trigger('onRequestAnimation') とするべきか、
$.project.sidebar.trigger('onRequestAnimation') とするべきか。
後者の場合はシングルトンが前提になっている。
なので、サイトにサイドバーが2つ以上必要になった場合に破綻する。
そして安直にこの問題を避けるとこういう感じになる。
(function($, undefined) { $.project = $.project || {}; $.project.sidebar = (function() { var event = $({}); return { create: function() { // Factory Method }, trigger: function() { $.fn.trigger.call(event, arguments); }, on: function() { $.fn.on.call(event, arguments); }, off: function() { $.fn.off.call(event, arguments); } } })(); }).apply(this, jQuery);
これで個々にサイドバーを $.project.sidebar.create() で作れるようになった。
また、インスタンスが出来ていない状態でもイベントを扱えるように $.project.sidebar.trigger 等を用意した。
しかしこれだと個々のサイドバーのイベントすべてを一括で扱ってしまうのであまり良くない。
なので、 $.project.sidebar をコンストラクタかファクトリにして event を書くインスタンス毎に生成させる。
つまり、$.project.sidebar().create() みたいな感じに。
前者の $('#sidebar').trigger('onRequestAnimation') はどうか。
でもこれを直接扱うとHTML構造に依存したサイドバー実装になってしまう。
各コンポーネントの疎結合は守りたい。これだとグローバルオブジェクトと変わりない。
(ここで言うグローバルオブジェクトはJavaScriptでの言葉ではなくプログラミング一般での意味)
じゃあ $('#sidebar') を渡してインスタンス化すればいいんじゃね?
ということでよくある形に。
(function($, undefined) { var createSidebar = function() { return ...; }; $.fn.sidebar = function() { var sidebar = createSidebar(); sidebar.on('onRequestAnimation', function() { // this.animate(...); }); }; }).apply(this, jQuery);
呼び出し側はこんな感じ
jQuery(function($) { var sidebar = $('#sidebar').sidebar(); $('#sidebar').on('mouseover', function() { sidebar.trigger('onRequestAnimation'); }); });
これだと最初のパターンと2番めのパターンがうまく融合してる感。
jQuery UI やら Twitter Bootstrap でよく見る形ですね。
僕は最近最後のパターンを使用しているんですが、
$.fn.sidebar 側が $(document).on でイベントを補足しまくっており、うーんな感じに。
document のイベントの補足はオプションで抑制できるようにしたりすれば良いのかな。
このあたりのパターンを良く聞かないのは僕の勉強不足なのか、jQuery UI のプラグインでええやろ!なのか。
そしてつらつらと書いてきましたが、まだ jQuery UI も Twitter Bootstrap も内部コード見たことないんですよねー。
という訳で、その2つのライブラリのお勉強をしてからまた記事書こうかなーと。
「いやいや、最近のパターンは普通こうだから」みたいなツッコミお待ちしております。