106

問題

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

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

サンプルコード

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

... // Around 75 more of this

function update_html(){ .... }

...

その他のサンプルコード

結論

このコードを最適に使用できるように整理し、同じことを繰り返したり、新しい機能を追加したり、古い機能を更新したりできるようにする必要があります。私は自分でこれに取り組んでいきます。一部のセレクターは 100 行のコードにすることができ、他のセレクターは 1 行require.jsです。私はこの基準に適合する可能性のある解決策を受け入れており、リソース/例へのリンクは常にプラスです.

ありがとう。

4

8 に答える 8

102

役に立つかもしれないし、役に立たないかもしれないいくつかの簡単なことを説明します。明らかなものもあれば、非常に難解なものもあります。

ステップ 1: コードを区画化する

コードを複数のモジュール単位に分割することは、非常に優れた最初のステップです。「一緒に」機能するものを切り上げて、それらを独自の小さなケースに入れてください。今のところフォーマットについて心配する必要はありません。インラインのままにしておいてください。構造は後ほど。

たとえば、次のようなページがあるとします。

ここに画像の説明を入力

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

その後、Grunt などのツールを使用して、JS を単一のユニットに再構築できます。

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

RequireJS や CommonJS などのライブラリを使用して、AMDと呼ばれるものを実装します。Asynchronous Module Loading を使用すると、コードが何に依存しているかを明示的に記述できるため、ライブラリ呼び出しをコードにオフロードできます。文字通り「これには 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 などもあります。リストは続きます。

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

ビューは、マークアップとそれに関連付けられたすべてのイベントを表します

コントローラーはビジネス ロジックを表します。つまり、コントローラーはページに対して、読み込むビューと使用するモデルを指示します。

これは重要な学習ステップになりますが、賞品はそれだけの価値があります。スパゲッティよりもクリーンでモジュール化されたコードが好まれるからです。

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

コード固有の変更

コードの特定の改善点を次に示します。

 $('.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);

これは、標準ではないイベントや作成イベントがある場合にルールを登録するための非常に強力な方法です。これは、pub/sub 通知システムと組み合わせて、要素を作成するたびに発生するイベントにバインドすると、非常に厄介です。Fire'n'forget モジュラー イベント バインディング!

于 2013-05-26T15:09:34.010 に答える
13

以下は、require.js を使用して、現在のコードベースを複数のファイルに分割する簡単な方法です。コードを 2 つのファイルに分割する方法を紹介します。その後、さらにファイルを追加するのは簡単です。

ステップ 1)コードの先頭に、App オブジェクト (または、MyGame などの任意の名前) を作成します。

var App = {}

ステップ 2)すべての最上位の変数と関数を変換して、App オブジェクトに所属させます。

それ以外の:

var selected_layer = "";

あなたがしたい:

App.selected_layer = "";

それ以外の:

function getModified(){
...
}

あなたがしたい:

App.getModified = function() {

}

この時点では、次のステップを完了するまでコードは機能しないことに注意してください。

手順 3)すべてのグローバル変数と関数の参照を変換して、App を通過させます。

次のようなものを変更します。

selected_layer = "."+classes[1];

に:

App.selected_layer = "."+classes[1];

と:

getModified()

に:

App.GetModified()

ステップ 4)この段階でコードをテストします。すべて動作するはずです。何かを見逃したため、最初はおそらくいくつかのエラーが発生する可能性があるため、先に進む前にそれらを修正してください。

ステップ 5) requirejs をセットアップします。コードが次の場所にあるWebサーバーから提供されるWebページがあるとします。

www/page.html

そしてjquery

www/js/jquery.js

これらのパスがこれとまったく同じでない場合、以下は機能せず、パスを変更する必要があります。

requirejsをダウンロードし、require.js をディレクトリに配置しますwww/js

で、page.htmlすべてのスクリプト タグを削除し、次のようなスクリプト タグを挿入します。

<script data-main="js/main" src="js/require.js"></script>

www/js/main.jsコンテンツで作成:

require.config({
 "shim": {
   'jquery': { exports: '$' }
 }
})

require(['jquery', 'app']);

次に、手順 1 ~ 3 で修正したすべてのコード (唯一のグローバル変数は App である必要があります) を次の場所に配置します。

www/js/app.js

そのファイルの一番上に、次のように入力します。

require(['jquery'], function($) {

一番下に:

})

次に、ブラウザに page.html をロードします。アプリが動作するはずです!

ステップ 6)別のファイルを作成する

ここがあなたの仕事が報われるところです、あなたはこれを何度も行うことができます。

www/js/app.js$ と App を参照するコードをいくつか抜き出します。

例えば

$('a').click(function() { App.foo() }

中に入れてwww/js/foo.js

そのファイルの一番上に、次のように入力します。

require(['jquery', 'app'], function($, App) {

一番下に:

})

次に、www/js/main.js の最後の行を次のように変更します。

require(['jquery', 'app', 'foo']);

それでおしまい!コードを独自のファイルに入れたいときはいつでもこれを行ってください!

于 2013-05-28T20:11:29.837 に答える
10

あなたの質問とコメントについては、コードを Backbone のようなフレームワークに移植したり、Require. できるだけ簡単な方法で、既に持っているコードを整理するためのより良い方法が必要なだけです。

2000 行以上のコードをスクロールして、作業したいセクションを見つけるのは面倒だと理解しています。解決策は、機能ごとに 1 つずつ、異なるファイルにコードを分割することです。たとえばsidebar.jscanvas.jsなどです。次に、Grunt を使用してそれらを結合し、Usemin を使用して、次のようなものを作成できます。

あなたのhtmlで:

<!-- build:js scripts/app.js -->
<script src="scripts/sidebar.js"></script>
<script src="scripts/canvas.js"></script>
<!-- endbuild -->

Gruntfile で:

useminPrepare: {
  html: 'app/index.html',
  options: {
    dest: 'dist'
  }
},
usemin: {
  html: ['dist/{,*/}*.html'],
  css: ['dist/styles/{,*/}*.css'],
  options: {
    dirs: ['dist']
  }
}

Yeoman を使用する場合は、これらすべてのボイラープレート コードが提供されます。

次に、各ファイル自体について、ベスト プラクティスに従い、すべてのコードと変数がすべてそのファイルにあり、他のファイルに依存していないことを確認する必要があります。これは、あるファイルの関数を別のファイルから呼び出すことができないという意味ではありません。ポイントは、変数と関数をカプセル化することです。名前空間に似たもの。すべてのコードをオブジェクト指向に移植したくないと仮定しますが、多少のリファクタリングを気にしない場合は、モジュール パターンと呼ばれるものと同等のものを追加することをお勧めします。次のようになります。

sidebar.js

var Sidebar = (function(){
// functions and vars here are private
var init = function(){
  $("#sidebar #sortable").sortable({
            forceHelperSize: true,
            forcePlaceholderSize: true,
            revert: true,
            revert: 150,
            placeholder: "highlight panel",
            axis: "y",
            tolerance: "pointer",
            cancel: ".content"
       }).disableSelection();
  } 
  return {
   // here your can put your "public" functions
   init : init
  }
})();

次に、このコードを次のようにロードできます。

$(document).ready(function(){
   Sidebar.init();
   ...

これにより、コードをあまり書き直すことなく、より保守しやすいコードを作成できます。

于 2013-05-28T18:04:58.227 に答える
6

javascript コードを標準的な方法で編成するには、javascript MVC フレームワークを使用します。

利用可能な最高の JavaScript MVC フレームワークは次のとおりです。

JavaScript MVC フレームワークを選択するには、非常に多くの要素を考慮する必要がありました。プロジェクトにとって重要な要因に基づいて最適なフレームワークを選択するのに役立つ次の比較記事をお読み ください。

フレームワークでRequireJSを使用して、非同期の js ファイルとモジュールの読み込みをサポートすることもできます。
JS モジュールのロードを開始するには、以下を参照してください:
http://www.sitepoint.com/understanding-requirejs-for-effective-javascript-module-loading/

于 2013-05-29T13:14:43.903 に答える
4

コードを分類します。このメソッドは私を大いに助けており、どのjsフレームワークでも機能します:

(function(){//HEADER: menu
    //your code for your header
})();
(function(){//HEADER: location bar
    //your code for your location
})();
(function(){//FOOTER
    //your code for your footer
})();
(function(){//PANEL: interactive links. e.g:
    var crr = null;
    $('::section.panel a').addEvent('click', function(E){
        if ( crr) {
            crr.hide();
        }
        crr = this.show();
    });
})();

お好みのエディター (Komodo Edit が最適です) で、すべてのエントリを折りたたんで折りたたむと、タイトルだけが表示されます。

(function(){//HEADER: menu_____________________________________
(function(){//HEADER: location bar_____________________________
(function(){//FOOTER___________________________________________
(function(){//PANEL: interactive links. e.g:___________________
于 2013-05-31T13:42:33.100 に答える
3

私は提案します:

  1. イベント管理のパブリッシャー/サブスクライバー パターン。
  2. オブジェクト指向
  3. 名前空間

ジェシカの場合、インターフェイスをページまたは画面に分割します。ページまたは画面はオブジェクトにすることができ、一部の親クラスから拡張できます。PageManager クラスを使用して、ページ間の相互作用を管理します。

于 2013-05-26T15:14:19.700 に答える
2

Backbone などを使用することをお勧めします。Backbone は RESTFUL 対応の JavaScript ライブラリです。Ik を使用すると、コードがよりクリーンで読みやすくなり、requirejs と一緒に使用すると強力になります。

http://backbonejs.org/

http://requirejs.org/

Backbone は実際のライブラリではありません。これは、JavaScript コードに構造を与えるためのものです。jquery、jquery-ui、google-maps などの他のライブラリを含めることができます。私の意見では、バックボーンは、オブジェクト指向およびモデル ビュー コントローラー構造に最も近い JavaScript アプローチです。

ワークフローについても.. PHP でアプリケーションを構築する場合は、Laravel ライブラリを使用します。RESTfull 原則と共に使用すると、Backbone で問題なく動作します。Laravel Framework へのリンクと、RESTfull API の構築に関するチュートリアル:

http://maxoffsky.com/code-blog/building-restful-api-in-laravel-start-here/

http://laravel.com/

以下は nettuts のチュートリアルです。Nettuts には高品質のチュートリアルがたくさんあります。

http://net.tutsplus.com/tutorials/javascript-ajax/understanding-backbone-js-and-the-server/

于 2013-05-26T15:00:42.087 に答える
0

おそらく、yeoman http://yeoman.io/などのツールを使用して、開発ワークフロー全体の実装を開始する時が来ました。これは、すべての依存関係、ビルド プロセス、および必要に応じて自動化されたテストを制御するのに役立ちます。最初は大変な作業ですが、一度実装すると、将来の変更がはるかに簡単になります。

于 2013-05-24T14:12:17.687 に答える