1. ホーム
  2. javascript

[解決済み] jQuery/JavaScriptコードの最適な整理方法(2013年)【非公開

2022-11-11 14:27:13

質問

問題点

この回答は以前にも回答されていますが、古くて最新ではありません。私は 2000 行以上のコードを 1 つのファイルにまとめていますが、ご存知のように、これは特にコードを調べたり新しい機能を追加したりするときに悪い習慣です。私は、現在および将来のために、私のコードをよりよく整理したいと思います。

私は、多くのボタン、UI 要素、ドラッグ、ドロップ、アクション リスナー/ハンドラー、および複数のリスナーが同じ関数を使用できるグローバル スコープの関数を持つツール (単純な Web サイトではありません) を構築していることを言及すべきです。

コード例

$('#button1').on('click', function(e){
    // Determined action.
    update_html();
});

... // Around 75 more of this

function update_html(){ .... }

...

その他のコード例

結論

私は本当に、このコードを最大限に活用し、繰り返さないように整理し、新しい機能を追加し、古いものを更新できるようにする必要があります。私は自分ひとりでこれに取り組むつもりです。あるセレクタは 100 行のコードになることもあれば、1 行のコードになることもあります。私は、少し見てみました。 require.js を少し見てみましたが、ちょっと繰り返しが多く、実際には必要以上のコードを書いていることがわかりました。私はこの基準に適合する任意の可能な解決策にオープンしており、リソース/例へのリンクは常にプラスです。

ありがとうございます。

どのように解決するのですか?

あなたの役に立つかもしれない、あるいは役に立たないかもしれない、いくつかの簡単なことについて説明します。いくつかは明白かもしれませんし、いくつかは非常に難解かもしれません。

ステップ 1: コードを分割する

コードを複数のモジュール単位に分離することは、非常に良い最初のステップです。一緒に動作するものを集め、それらを独自の小さなカプセル化されたユニットに入れます。構造は後回しにしましょう。

では、こんなページがあったとします。

メンテナンスを容易にするために、すべてのヘッダー関連のイベントハンドラ/バインダーがそこにあるように、区分けすることは理にかなっています(そして、1000行をふるいにかける必要はありません)。

その後、Gruntのようなツールを使って、JSを単一のユニットに戻すために再ビルドすることができます。

ステップ1a: 依存関係の管理

RequireJSやCommonJSなどのライブラリを使用して、以下のようなものを実装します。 AMD . 非同期モジュール読み込みでは、コードが何に依存しているかを明示的に記述することができ、それによってライブラリの呼び出しをコードにオフロードすることができます。文字通り「This needs jQuery"」と言えば、AMDはそれをロードし、コードを実行します。 jQueryが利用可能な場合 .

これはまた、隠された宝石を持っています:ライブラリの読み込みは、DOMが準備された瞬間、それ以前には行われません。これにより、ページの読み込みを中断することがなくなります!

ステップ 2: モジュール化

ワイヤーフレームをご覧ください。2つの広告ユニットがあります。イベントリスナーを共有していることがほとんどでしょう。

このステップでのあなたの仕事は、コードの中で繰り返されているポイントを特定し、これらすべてを統合して モジュールに統合することです。 . モジュールは、今すぐすべてを包含することになります。順次、分割していく予定です。

このステップの全体的なアイデアは、ステップ1から行って、すべてのコピーパスタを削除し、疎結合のユニットに置き換えることです。つまり、代わりに

ad_unit1.js

 $("#au1").click(function() { ... });

ad_unit2.js

 $("#au2").click(function() { ... });

持つことになる。

ad_unit.js :

 var AdUnit = function(elem) {
     this.element = elem || new jQuery();
 }
 AdUnit.prototype.bindEvents = function() {
     ... Events go here
 }

page.js :

 var AUs = new AdUnit($("#au1,#au2"));
 AUs.bindEvents();

を区分けすることができます。 イベント マークアップ を追加し、繰り返しをなくすことができます。これはかなりまともなステップで、後でさらにこれを拡張します。

ステップ3:フレームワークを選ぶ

モジュール化して繰り返しをさらに減らしたいのであれば、MVC(モデル - ビュー - コントローラ)アプローチを実装する素晴らしいフレームワークがたくさん存在します。私のお気に入りはBackbone/Spineですが、他にもAngular、Yii、...といったものがあります。数え上げればきりがありません。

A モデル はデータを表します。

A 表示 は、マークアップとそれに関連するすべてのイベントを表します。

A コントローラ はビジネスロジックを表します。言い換えれば、コントローラはページにどのビューをロードし、どのモデルを使用するかを伝えます。

これは重要な学習ステップになるでしょうが、その価値はあります。

他にもできることはたくさんありますが、これらは単なるガイドラインとアイデアです。

コード固有の変更

以下は、コードに対する具体的な改善点です。

 $('.new_layer').click(function(){

    dialog("Create new layer","Enter your layer name","_input", {

            'OK' : function(){

                    var reply = $('.dialog_input').val();

                    if( reply != null && reply != "" ){

                            var name = "ln_"+reply.split(' ').join('_');
                            var parent = "";

                            if(selected_folder != "" ){
                            parent = selected_folder+" .content";
                            }

                            $R.find(".layer").clone()
                            .addClass(name).html(reply)
                            .appendTo("#layer_groups "+parent);

                            $R.find(".layers_group").clone()
                            .addClass(name).appendTo('#canvas '+selected_folder);

            }

        }

    });
 });

と書いた方がよいでしょう。

$("body").on("click",".new_layer", function() {
    dialog("Create new layer", "Enter your layer name", "_input", {
         OK: function() {
             // There must be a way to get the input from here using this, if it is a standard library. If you wrote your own, make the value retrievable using something other than a class selector (horrible performance + scoping +multiple instance issues)

             // This is where the view comes into play. Instead of cloning, bind the rendering into a JS prototype, and instantiate it. It means that you only have to modify stuff in one place, you don't risk cloning events with it, and you can test your Layer stand-alone
             var newLayer = new Layer();
             newLayer
               .setName(name)
               .bindToGroup(parent);
          }
     });
});

コードの早い段階で

window.Layer = function() {
    this.instance = $("<div>");
    // Markup generated here
};
window.Layer.prototype = {
   setName: function(newName) {
   },
   bindToGroup: function(parentNode) {
   }
}

突然ですが、コピーペーストをせずにコードのどこからでも標準レイヤーを作成する方法ができました。あなたはこれを5つの異なる場所で行っています。コピーペーストを5回分節約できたことになります。

もう1つ。

// アクションのルールセットラッパー

var PageElements = function(ruleSet) {
ruleSet = ruleSet || [];
this.rules = [];
for (var i = 0; i < ruleSet.length; i++) {
    if (ruleSet[i].target && ruleSet[i].action) {
        this.rules.push(ruleSet[i]);
    }
}
}
PageElements.prototype.run = function(elem) {
for (var i = 0; i < this.rules.length; i++) {
    this.rules[i].action.apply(elem.find(this.rules.target));
}
}

var GlobalRules = new PageElements([
{
    "target": ".draggable",
    "action": function() { this.draggable({
        cancel: "div#scrolling, .content",
        containment: "document"
        });
    }
},
{
    "target" :".resizable",
    "action": function() {
        this.resizable({
            handles: "all",
            zIndex: 0,
            containment: "document"
        });
    }
}

]);

GlobalRules.run($("body"));

// If you need to add elements later on, you can just call GlobalRules.run(yourNewElement);

これは、標準的でないイベント、または作成イベントがある場合に、ルールを登録するための非常に強力な方法です。これはまた、パブ/サブ通知システムと組み合わせたとき、および要素を作成するたびに発生するイベントにバインドしたときに、真剣にキックアスです。モジュール式イベント バインディングを使用すると、要素を作成するたびに起動します。