jqueryの下でjavascriptコードを組織する(js関数化)

9410 ワード

不思議な「$」関数から
「$」関数は、ドキュメントのロードが完了すると、単一のWebページで正常に動作する指定されたbuttonバインドイベントになります.しかし、他のページがあれば、このプロセスを繰り返さなければなりません.
 
  
Say Hello
<br>//when dom ready, do something. <br>//bind click event to a button. <br>$(function(){ <br>$('#sayHello').click(function(){ <br>alert('Hello world!'); <br>}); <br>}); <br>

もし私たちが別の行為のbuttonが必要ならどうしますか?たとえば、次のようになります.
 
  
Unlike it
<br>//when dom ready, do something. <br>//bind click event to a button. <br>$(function(){ <br>$('#sayUnlike').click(function(){ <br>alert('I unlike it.'); <br>}); <br>}); <br>

次に、もっと多くの問題が現れて、私たちはこのようなbuttonをたくさん必要として、これも難しくないようです.
 
  
Unlike it
<br>//Change to a class selector to match all the button elements. <br>$(function(){ <br>$('.sayUnlike').click(function(){ <br>alert('I unlike it.'); <br>}); <br>}); <br>

一つのページに同じ種類のbuttonが2種類現れましたが...
 
  
Say Hello
Unlike it
<br>$(function(){ <br>$('.sayHello').click(function(){ <br>alert('Hello world!'); <br>}); <br>$('.sayUnlike').click(function(){ <br>alert('I unlike it.'); <br>}); <br>}); <br>

しかし、すべてのページでこの2つのbuttonが使用されるわけではありません.ページに追加のセレクタを使用しないためには、classベースのセレクタのパフォーマンスがidセレクタに比べてオーバーヘッドが大きいため、すべてのdom要素を遍歴し、正規表現を使用してclass属性を一致させて条件を満たす要素を選択する必要があります.
 
  
if($page == 'A'){?>
<br>$(function(){ <br>$('.sayHello').click(function(){ <br>alert('Hello world!'); <br>}); <br>}); <br>
} ?>
if($page == 'B'){?>
<br>$(function(){ <br>$('.sayUnlike').click(function(){ <br>alert('I unlike it.'); <br>}); <br>}); <br>
} ?>

私たちのプロジェクトの機能はますます複雑になり、しばらくしてから、このようになりました.quick but dirty......
 
  
if($page == 'A' or $page == "C" and $page is not "D"){ ?>
<br>...... <br>
} ?>
if($page == "B" or $page == "E" and $page is not "X"){ ?>
<br>..... <br>
} ?>
if($page == "B" or $page == "E" or $page == "C"){ ?>
<br>..... <br>
} ?>

これは本当に大変ですね.すべてのイベントをバインドするには、1つのページに複数のコード断片をロードする必要があります.複数のjsファイルに異なるコードを分割すると、複数のページリソースのhttpリクエストが増加します.管理もユーザー体験も課題に直面します.より良い解決策を見つける必要があります.
class selectorのオーバーヘッドがこんなに大きい以上、1回のスキャンですべてのイベントをバインドできますか?試してみましょう
 
  
<br>//Register global name space. <br>var Yottaa = Yottaa || {}; <br>Yottaa.EventMonitor = function(){ <br>this.listeners = {}; <br>} <br>//Bind all event. <br>Yottaa.EventMonitor.prototype.subscribe=function(msg, callback){ <br>var lst = this.listeners[msg]; <br>if (lst) { <br>lst.push(callback); <br>} else { <br>this.listeners[msg] = [callback]; <br>} <br>} <br>// Create the event monitor instance. <br>var event_monitor = new Yottaa.EventMonitor(); <br>function load_event_monitor(root){ <br>var re = /a_(\w+)/; //using a regular expression to filter all event object. <br>var fns = {}; <br>$(".j", root).each(function(i) { <br>var m = re.exec(this.className); <br>if (m) { <br>var f = fns[m[1]]; <br>if (!f) { // . <br>f = eval("Yottaa.init_"+m[1]); <br>fns[m[1]] = f;// . <br>} <br>f && f(this); <br>} <br>}); <br>} <br>$(function(){ <br>// when dom ready, bind all event. <br>load_event_monitor(document); <br>}); <br>//Here is 2 sample components. <br>Yottaa.init_sayhello = function(obj){ <br>$(obj).click(function(){ <br>alert('Hello world!'); <br>}); <br>} <br>Yottaa.init_unlike = function(obj){ <br>$(obj).click(function(){ <br>alert('I unlike it.'); <br>}); <br>} <br>

私たちのDOM要素はこう書きます.
Say Hello
Say Unlike
このように見ると、ページのロード時にclass selector(上のコードではすべての'.j'の要素)を1回実行するだけで、イベントをバインドする必要があるすべての要素を見つけることができます.具体的には、どのコンポーネントがclass名の中のa_xxxが決めて、Yottaaに対応しています.init_xxxは、現在の要素の参照をパラメータとしてイベントロジックに入力します.
この処理モードでは、イベント処理の論理を再び手動で記述し、$(function(){......})に置く必要はありません.このような初期化関数では、コンポーネントの「コンテナ」に2つのclass:「j a_XXX」プログラムを加えるだけで、イベントバインド作業を完了することができます.coolではありませんか.一般的な展開/折りたたみ効果、全選択/逆選択効果、tab切り替えなど、他の簡単な機能でも使用できます.これが伝説の銀弾なのか?いいえ、そんなに簡単ではありません.私たちはこのような処理方法の弱点を見るべきです.
コンポーネントに初期化パラメータを渡すことはできません.
コンポーネントの包含関係を体現することはできないし,継承や多態などのオブジェクト向けの特性を利用してプログラムの作成と理解を容易にすることもできない.
一部の具体的な関連関係のコンポーネントは処理がやや面倒であり,合理的なイベント通知メカニズムがない.
最初の1つを見てみましょう.パラメータの伝達について、多くのシーンで複数のエントリのリストに対して、各エントリに対応して、メッセージリストやポートリストのようなサーバ側の番号が異なる点で、要素に一意のidを割り当てます.idプロパティを使用して、次のコードを見て、idプロパティでエントリに対応するサーバ側番号をjavascriptに伝え、次のイベントロジック処理でサーバコールバック関数パラメータの一部としてサーバ側に返すことができます.
 
  
<br>Yottaa.init_sampleajax = function(obj){ <br>$(obj).click(function(){ <br>var component_id = $(this).attr('id').split('-')[1]; <br>$.get('/server/controller/method', {id: component_id}, function(data){ <br>if(data){ <br>alert('Message from server: ' + data ); <br>} <br>}); <br>}); <br>} <br>
Show server message.
Another button with same action but different server side identifier.

より複雑なシーンでは、ページ上のinline codeを使用してコンポーネントに必要な情報を伝えることができます.
 
  
Yottaa.globalConst = {
User:{
familyName: "Jhone",
givenName: 'bruce'
},
Url:{
siteName: 'yottaa.com',
score: 98
}
}
Yottaa.componentMetaData = {
compoment_id_1:{ ...... },
component_id_2:{ ...... }
};

上では可能なコード組織方法について議論したが、すべてのプロジェクトに適用されるわけではない.現在の現状に対して、コストの小さい再構築案を見つけることだ.以下の点を考慮します.
要素を分離するイベントバインドコードとコンポーネントコード:コンポーネントコードにはjqueryライブラリ、関連拡張プラグイン、chartboxなどの私たちが作成したコンポーネントが含まれます.
イベントバインドおよび処理ロジック:異なるコンポーネントによって複数のモジュールに分割され、各モジュールは1つのfunctionに格納されます.
ページは、このページで初期化するモジュールを指定し、グローバルなイベントバインドによって統一的に処理されるリストを提供します.
コードの一部を説明します.
 
  
<br>function init_loginPanel = function(){ <br>var container = $('login_panel'); <br>$('#login_button').click(function(){ <br>...... <br>}); <br>} <br>function init_chart = function(){ <br>...... <br>} <br>//global static init method <br>Yottaa.initComponents = function(components){ <br>for(var i = 0;i<components.length;i++){ <br>if(typeof window[components[i]] == 'Function'){ <br>window[components[i]](); <br>} <br>} <br>} <br>// above is in the 'all-in-one' assets file which is compressed to one file in production. <br>var components = ['init_loginPanel', 'init_chart']; <br>var metaData = { <br>loginPanel: {}, <br>chart: {}, <br>...... <br>}; <br>$(function(){ <br>Yottaa.initComponents(components); <br>}); <br>//here is inline script on the page. <br>