js のコード ロジックはますます重くなるため、js ファイルには数千行が含まれる場合があり、これは開発やメンテナンスにとって非常に不利です。最近、ロジックの重い JS をモジュールに分割しています。requirejs と seajs のどちらを使用するか悩んだのですが、最終的には requirejs を使用することにしました。やっぱり公式文書のほうが専門的ですね…
しかし、完全な公式ドキュメントがあっても、jquery-ui の使用など、依然として多くの問題に遭遇します。
以下は、私が遭遇した問題とその解決策を段階的に説明したものです。
AMD と CMD の理解
AMD(非同期モジュール定義)の代表例はrequirejs、CMD(共通モジュール定義)の代表例はタオバオのseajsです。
これらに共通しているのは、どちらも js を非同期でロードすることです。ただし、require.js はロード直後に実行されるのに対し、seajs は main 関数に入って実行する必要があるまで実行されないという点が異なります。
seajsを使用すると初期読み込みや実行効率は高くなりますが、使用中にjsを取得して実行する場合があるためラグが発生し、ユーザーエクスペリエンスに影響を与える可能性があります(試していないので間違っていたら、驚かないでください)。また、requirejs は読み込まれたすべての js を最初に実行します。このとき、モジュール内にいくつかの実行メソッドがある場合、それらは希望する順序で実行されない可能性があります。
したがって、非同期プログラミングに慣れていて完全なドキュメントが必要な場合は、requirejs を使用することをお勧めします。実行順序に特別な要件を設けて開発を容易にしたい場合は、seajs を使用することもできます。
requirejs で循環依存関係の問題を解決する方法
定義したモジュール a がモジュール b を使用し、モジュール b がモジュール a を使用する場合、循環依存関係例外がスローされます。
たとえば、循環依存関係の例をここに書きました。
メインページ:
<!DOCTYPE html> <html> <head> </head> <body> <script data-main="test.js" src="lib/require.js"></script> </body> </html>
メインメソッド:
requirejs.config({ baseUrl: './' }); requirejs(['js/a'],function (a){ console.log("in test"); a.testfromb(); });
a.js モジュールでは、test() メソッドが b を呼び出すメソッドを提供し、testfromb() メソッドが b のメソッドを呼び出します
define(function(require){ var b = require("js/b"); console.log("in a"); return { atest:function(){ console.log("test in a"); }, testfromb:function(){ console.log("testfromb in a"); b.btest(); } } });
モジュール b では、a のメソッドが呼び出されます。
define(function(require){ var a = require("js/a"); console.log("in b"); return { btest:function(){ console.log("test in b"); a.atest(); } } });
これは a が b のメソッドを呼び出すのと同等ですが、b のメソッドは a のメソッドに依存するため、循環依存関係が作成されます。ブラウザでエラーが表示されます:
キャッチされないエラー: モジュール名「js/a」がコンテキストに対してまだロードされていません: _
公式ドキュメントによると、これは設計上の問題であり、可能な限り回避する必要があります。では、避けられない場合はどうすればいいのでしょうか?モジュール b は次のように変更できます:
define(function(require){ // var a = require("js/a"); console.log("in b"); return { btest:function(){ console.log("test in b"); require("js/a").atest(); } } });
ここでは、モジュールをロードする前に、test() メソッドが実行されるまで待機します。この時点でモジュール a は明らかにロードされています。出力情報を確認できます:
in b a.js:3 in a test.js:6 in test a.js:9 testfromb in a b.js:6 test in b a.js:6 test in a
同様に、a を変更すると機能しない可能性があります。これは、モジュールのロード順序が b から始まるためです。
循環依存関係のソース コードについては、クラウド ディスクを参照してください
requirejs で jquery を使用する方法
jquery を比較的簡単に使用したい場合は、対応する依存関係を main.js に直接追加するだけです。
requirejs.config({ baseUrl: './', paths:{ 'jquery':'lib/jquery' } }); requirejs(['jquery'], function ($){ $('#test').html('test'); });
如何在requirejs中使用jquery插件 对于jquery的插件,比较常见的做法都是传入一个jquery的对象,在这个jquery对象的基础上添加插件对应的方法。 首先需要添加jquery插件的依赖,这里用两个插件举例子——jquery-ui和jquery-datatables
requirejs.config({ baseUrl: './', paths:{ 'jquery':'lib/jquery', 'jquery-ui':'lib/jquery-ui', 'jquery-dataTables':'lib/jquery.dataTables' }, shim:{ 'jquery-ui':['jquery'], 'jquery-dataTables':['jquery'] } }); requirejs(['jquery','jquery-ui','jquery-dataTables'], function ($){ .... });
由于jquery插件都需要依赖于jquery,因此可以在shim中指定依赖关系。 除了上面这种使用方法,也可以使用commonJS风格的调用:
define(function(require){ var $ = require('jquery'); require('jquery-ui'); require('jquery-dataTables'); //下面都是测试,可以忽略 var _test = $('#test'); _test.selectmenu({ width : 180, change : function(event, ui) { console.log('change'); } }); return { test:function(){ //测试jquery-ui _test.append($('<option>test1</option><option>test1</option>')); _test.selectmenu("refresh"); //测试jquery-datatables var _table = $('table'); _table.dataTable(); } } });
ただし、上記のコードを実行すると、例外が報告されます:
キャッチされない TypeError: _table.dataTable は関数ではありません
dataTables は require スタイルのモジュールではないため、このように直接導入すると内部の匿名関数が実行されません。最後の行で $ オブジェクトを渡して、その匿名関数を変更できます:
*/ return $.fn.dataTable; //}));原来是这样 }($)));//这里增加执行这个匿名函数,并且传入$对象。 }(window, document));
これもインターネットで探す方法ですが、経験不足による原理です…
サンプル コードはクラウド ディスクを参照してください。インポートされたリソースは完了していないため、エラーが報告されますが、UI プラグインが実行できたことは成功したことを意味するため、無視できます。
requirejs で jquery-ui を使用する際の問題
requirejs は js ファイルのロード直後に実行されるため、jquery ui プラグインが DOM ページを更新する必要がある場合、ページのイベントが失敗する可能性があります。
たとえば、モジュールがロードされた後、クリック イベントはページ上の特定の要素 $('#test') にバインドされます。ただし、特定の UI プラグインを使用すると、プラグインが DOM 要素を再描画するため、テストに対応するクリック イベントが無効になります。
解決策:
•DOM 要素がレンダリングされるまでイベント バインディングを遅らせ、その後バインディングを手動でトリガーします。
•DOM要素のイベントバインディングの代わりにイベントキャプチャを使用することもできます(面倒すぎる...推奨されません)。
require("xxx").initEvents(); 一般的なシナリオ:
たとえば、ページ上で jquery-steps UI プラグインを使用すると、ページが再レンダリングされます。これにより、最初にバインドしたイベントが無効になってしまいました。JS ページが再構築されるまでバインドを延期し、その後再度バインドすることしかできませんでした。
上記の記事「RequireJS と JQuery をベースにしたモジュラー プログラミング - よくある質問の包括的な分析」は、編集者が共有したすべての内容です。参考にしていただければ幸いです。また、Script Home をサポートしていただければ幸いです。