requirejs+angular+angular-route HTML 5単ページアーキテクチャについて


周知のように、今ではモバイルWebappが増えています.例えば、天猫、京東、国美などは良い例です.Webappでは、単一ページアーキテクチャの体験が最もよく、オリジナルappに似ています.簡単に言えば、シングルページアプリは頻繁にページを切り替える必要がなく、ローカルにリフレッシュでき、ロード全体がスムーズになります.
くだらないことは多く言わないで、直接本題に着いて、私自身が理解しているいくつかの単ページアーキテクチャを浅く話しましょう:-1、requirejs+angular+angular-route(+zepto)最後にこのzeptoはあってもなくてもいいです.主にチームの中で本当にangularを不快にしている学生に、柔軟にページのいくつかの内容を修正することができます.もちろん、厳格なプロジェクトにはzeptoが現れるべきではありません.-2、requirejs+backbone+zepto+templateこの方案はもっと柔軟で、MVCの味がもっと濃くて、カスタマイズしたtemplateテンプレートライブラリを使う-3、requirejs+route+templateという方案は最も柔軟で、紅塵を見破って、簡単な業務に対して最も簡単な方法で、ルートとテンプレートだけを必要として、MVCフレームワーク-4、react個人の感じを使わないで、reactはview層のコンポーネントに偏っており,nativeであるが,実施の難易度はやや高い
プロジェクトアーキテクチャといえば、多くの点を考慮することが多い.
  • が便利です.例えばjqueryを使用すると、jqueryを使用していないよりも便利になるに違いないので、ほとんどのサイトは類似のライブラリにアクセスしています.
  • パフォーマンスの最適化.読み込み速度、レンダリング効率が含まれます.
  • コード管理.大規模なプロジェクトはコードのモジュール化を考慮する必要があり、モジュール間の低結合高集約は、チームの協力効率のためである.
  • 拡張性.これは言うまでもない.
  • 学習コスト.一つのフレームワークがどんなに良くても、チームの新しいメンバーは把握しにくく、学習の難易度が高く、結果的にコードの混乱を招きやすい.

  • 実際の経験から見ると、便利さは必然的に最も重要な地位であり、それ以外はコード管理であるべきである.チームワークの過程で、さまざまなコラボレーション、コードの衝突など、優れたフレームワークにさまざまな奇妙な難題をもたらします.そのため、良いフレームワークがあれば十分ではありません.私たちは自分のビジネスとチームの状況に応じて、必要に応じてフレームワークを裁断したり修正したりして、最適な実施案を見つける必要があります.
    次に、3つのエッセイに分けて、私の心の中の前の3つのアーキテクチャの良い実施案を紹介します.最後の3つは、前の3つは道が違うような気がしますが、自分の道が足りないので、しばらくは言いません.
    这篇,先说第1种:requirejs+angular+angular-route
    モバイル側の単一ページWebは、モジュール化されていない場合、ページ初期化時にすべてのjsとすべてのテンプレートをロードするため、モジュール化管理が非常に重要です.この点はみんな理解している.したがって、requirejsまたは同様のモジュール化フレームワークは不可欠である.requirejsが流行しているので、gruntに合わせて自動化ツールをセットすることができます.これを例に挙げましょう.
    まず、demoプロジェクトの全体的なアーキテクチャを見てみましょう.
    クラスライブラリのほか、ビジネスコードはすべてモジュールでディレクトリを区分して、このようにして実際の開発の中で便利で、モジュールによってjsとhtmlを結合して合併して、多くの人が並列に開発することにも有利で、それぞれ異なるモジュールを修正して、互いに影響しません.
    また、3つのポイントのルートディレクトリファイルについて説明します.
  • index.html、これは単一ページの唯一のhtmlで、その他はすべてクリップのテンプレート(tpl.html)です.一般的にこのhtmlをダイナミックサーバに配置して、ゼロキャッシュを維持することができます.同時に、ここでは各種jsバージョンの制御情報と必要なユーザーデータを携帯することができます.
  • main.js、これはrequirejsによって導入された最初のビジネスjsであり、主にrequirejsを構成する.
  • router.js,これはウェブサイト/app全体のルーティング構成であり,実際の配置ではmain.jsとrouter.jsマージ.

  • まずindexを見てみましょうhtmlは何をする必要がありますか?
    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title>Angular & Requirejs</title>
    </head>
    <body>
    <div id="container" ng-view></div>
    <script data-baseurl="./" data-main="main.js" src="libs/require.js" id="main"></script>
    </body>
    </html>

    angularの書き方に対して、ここではrequirejsを使用してすべてのモジュールを管理するのでindex.htmlにはangularなどを導入する必要はありませんが、アプリケーション全体のビュー領域として機能するng-view属性付きdivが設定されています.Data-baseurlは追加の属性であり、主な利点はhtml(0キャッシュ)でjsのurlを簡単に変更できることです.Data-mainはrequirejsの標準的な書き方で、スキップして言わない.
    ステップ2js、すなわちrequirejsの構成
    'use strict';
    
    (function (win) {
        //  baseUrl
        var baseUrl = document.getElementById('main').getAttribute('data-baseurl');
    
        /* *      */
        var config = {
            baseUrl: baseUrl,           //      
            paths: {                    //             baseUrl      ,        
                underscore: 'libs/underscore',
                angular: 'libs/angular',
                'angular-route': 'libs/angular-route',
                text: 'libs/text'             //  requirejs  html     
            },
            shim: {                     //      requirejs       。  underscore    ,          '_'。  shim          ,        '_'     ,      exports,     requirejs    
                underscore: {
                    exports: '_'
                },
                angular: {
                    exports: 'angular'
                },
                'angular-route': {
                    deps: ['angular'],   //      
                    exports: 'ngRouteModule'
                }
            }
        };
    
        require.config(config);
    
        require(['angular', 'router'], function(angular){
            angular.bootstrap(document, ['webapp']);
        });
    
    })(window);

    requirejsの構文は,長い話で,コードに簡単に注釈をつけた.詳細については、公式サイトを参照してください.http://requirejs.org/;Angularは以下を参照できます.https://docs.angularjs.org/guide/filter
    ここでrequirejsを構成したら、angularとangularのルーティング構成を導入し、
    angular.bootstrap(document, [‘webapp’]); 手動でangularを起動します.ここでwebappはrouterです.jsで定義されたangular module.
    3つ目はこのrouterを構成することです
    define(['angular', 'require', 'angular-route'], function (angular, require) {
    
        var app = angular.module('webapp', [
            'ngRoute'
        ]);
    
        app.config(['$routeProvider', '$controllerProvider',
            function($routeProvider, $controllerProvider) {
                $routeProvider.
                    when('/module1', {
                        templateUrl: 'module1/tpl.html',
                        controller: 'module1Controller',
                        resolve: {
                            /*   key      controller ,        function    ,  promise  resolve  。           ,angular             controller  (  keyName): controllers.controller('module2Controller', ['$scope', '$http', 'keyName', function($scope, $http, keyName) { }]); */
                            keyName: function ($q) {
                                var deferred = $q.defer();
                                require(['module1/module1.js'], function (controller) {
                                    $controllerProvider.register('module1Controller', controller);      //        controller,      ,   
                                    deferred.resolve();
                                });
                                return deferred.promise;
                            }
                        }
                    }).
                    otherwise({
                        redirectTo: '/module1'      //angular       
                    });
            }]);
    
        return app;
    });

    上記のコードは長いように見えますが、実際には短いです.緑の注釈が山積みになっているので、へへへ...angular-routeを使ったことがある場合は、ここの構文は簡単ですが、使ったことがない場合は、angular-routeソースのコメントを直接読むことをお勧めします.非常にはっきりしています.簡単に言えば、when関数は、templateとcontrollerに対応するルーティングルールを構成します.otherwiseはデフォルトのルーティングです.つまり、未定義のパスに遭遇したときにどのようにジャンプするかです.requirejsが使用されていない場合は、ルーティング構成の前に完全なコントローラをロードする必要があります.angular-routeでは、HTMLテンプレートを切り替え、再コンパイルし、新しいcontrollerをバインドする必要があります.しかしここでrequirejsを使うと、事情が変わります.私たちはオンデマンドでロードしなければなりません.ページがロードされたばかりですべてのコントローラがloadして帰ってくることはできません.これでどれだけのトラフィックがかかりますか.のそこで,angular-routeが提供するresolve機能,すなわちルーティングhtmlを変更する前にresolveの中でやるべきことを先に完成させる.resolveの書き方は特殊で、key:valueオブジェクトを受け入れています.keyNameはcontrollerにインポートされます(controllerに依存が明記されている場合).valueは関数であるべきで、関数の書き方はcontrollerに似ており、angularはパラメータ名に基づいて対応する依存サービス、例えば$q$routeを自動的にインポートします.上記例ではmodule 1.jsはモジュール1のcontrollerを定義し,その後コードを参照する.このコントローラは、ルーティング構成前に存在しなかったため、動的に登録する必要があります.つまり、
    $controllerProvider.register('module1Controller', controller);

    ステップ4では、モジュール1のコントローラがどのように書かれているかを見てみましょう.
    define(['angular'], function (angular) {
    
        //angular     controller      ,       
        return function($scope, $http, $interval){
            $scope.info = 'kenko';      // view/      
    
            //    cgi    ,     ,      ,      $('#xxx').html(xxx)
            $http.get('module2/tpl.html').success(function(data) {
                $scope.info = 'vivi';
            });
    
            var i = 0;
            //angularjs      setTimeout setInterval,       ,    $timeout $interval,      angular      
            $interval(function () {
                i++;
                $scope.info = i;
            }, 1000);
        };
    });

    angularには牛が追い詰める機能がたくさんありますが、実際には私の業務は簡単すぎて、使えません.ここでは3つの最も簡単な状況しか示していません.ここでは,双方向バインドによりcgiを引いたりdomを修正したりする操作が非常に簡単になったと言わざるを得ない.すべてが解決したようだ?このようなモジュール化はすでに良いようで、あるモジュールにジャンプしたときに対応するhtmlとcontroller jsをロードします.しかし、究極のチームを追求するには、モジュールのhtmlとjsをパッケージ化し、1回のリクエストを引き返すことで、HTTPリクエストの時間を大幅に減らすことができます.現在angular-routeに従って、templateUrlを利用してhtmlファイルを1つだけ引き出すことができます.では、次に、頭を捻って、修正しましょう.
    ステップ5では、angular-routeを変更し、HTMLとjsパッケージのロードを実現します.
    function ngViewFillContentFactory($compile, $controller, $route) {
      return {
        restrict: 'ECA',
        priority: -400,
        link: function(scope, $element) {
          var current = $route.current,
              locals = current.locals;
    
          $element.html(current.template);  //   locals.$template

    まず、angular-routeのソースコードを修正します.このソースコードはとても簡素で、あまり悩まないで、厳しく修正すればいいです.また、なぜ知っているのか、あるいはここで修正したいのかを聞きたいです.咳咳咳咳、私は大きく振ってangular-routeの作者を知っていると言いますか?....冗談です.作者の名前は何ですか.私は探していません.作者を知っていると言っています.実は徐々に調整して、少し変数を加えて検索して、いくつかのおかしいことを発見して、このナイフを作りました.また、専門家が板をたたくので、このようにむやみに修正すると、間違いなく欠点をもたらします.はい、私は自分で問題があるかどうかを徹底的に検査していないと言わざるを得ませんが、実際の状況から見ると、しばらく問題に遭遇していません.次に、新しいwhen構成を行います.
           when('/module2', {
                        template: '',
                        controller: 'module2Controller',
                        resolve:{
                            keyName: function ($route, $q) {
                                var deferred = $q.defer();
                                require(['module2/module2.js'], function (module2) {
                                    $controllerProvider.register('module2Controller', module2.controller);
                                    $route.current.template = module2.tpl;
                                    deferred.resolve();
                                });
                                return deferred.promise;
                            }
                        }
                    })

    ここでmodule 2を例にとると、module 1とは異なり、ここで初期に設定されたtemplateは空の文字列であり、resolveでrequireが戻ってきたら、$routeを動的に変更する.current.template. 私は知っているので、この修正はangular-routeがHTMLを修正する前に、つまり小さなトリックが効果的になることができます.では、module 2の書き方を見てみましょう.
    define(['angular', 'text!module2/tpl.html'], function (angular, tpl) {
    
        //angular     controller      ,       
        return {
            controller: function ($scope, $http, $interval) {
                $scope.date = '2015-07-13';
            },
            tpl: tpl
        };
    });

    これによりhtmlテンプレートはangular-routeで引き継ぐのではなく、requirejsでロードされ、制御できる範囲と柔軟性が大きくなります.ただし、ここでcontrollerの関数の書き方は、圧縮混同時に元のパラメータ名が失われる可能性があるため、明示的な注入方式を採用することもできます.
    //              ,angular  controller   ,    $inject
        controller.$inject = ['$scope'];
        function controller(s){
            s.date = '2015-07-13';
        }
        return {controller:controller, tpl:tpl};

    ここまで、アーキテクチャ全体が基本的に成形され、webappの各モジュールは非常に独立しており、Webサイトのオープン速度と共同開発に非常にメリットがあります.しかし、ルーティングテーブルの構成はまだ少し複雑で、毎回みんながたくさんのコードを書かなければなりません.これは私たちが望んでいるものではありません.では、共通コードを抽出して、最適化することができます.
    第6歩は、ルーティングテーブルを最適化し、真の構成化になります.
    define(['angular', 'require', 'angular-route'], function (angular, require) {
    
        var app = angular.module('webapp', [
            'ngRoute'
        ]);
    
        app.config(['$routeProvider', '$controllerProvider',
            function($routeProvider, $controllerProvider) {
    
                var routeMap = {
                    '/module2': {                           //  
                        path: 'module2/module2.js',         //       
                        controller: 'module2Controller'     //     
                    }
                };
                var defaultRoute = '/module2';              //         
    
                $routeProvider.otherwise({redirectTo: defaultRoute});
                for (var key in routeMap) {
                    $routeProvider.when(key, {
                        template: '',
                        controller: routeMap[key].controller,
                        resolve:{
                            keyName: requireModule(routeMap[key].path, routeMap[key].controller)
                        }
                    });
                }
    
                function requireModule(path, controller) {
                    return function ($route, $q) {
                        var deferred = $q.defer();
                        require([path], function (ret) {
                            $controllerProvider.register(controller, ret.controller);
                            $route.current.template = ret.tpl;
                            deferred.resolve();
                        });
                        return deferred.promise;
                    }
                }
    
            }]);
    
        return app;
    });

    routeMapはサーバから直接出て、0キャッシュを実現し、徹底的にデカップリングし、チームの協力を容易にすることができます.最後に、requirejsとangularにはモジュール管理がありますが、2つの概念が一致していません.ここで私の見方を説明します.
    requirejsモジュール管理は、コードモジュール化だけでなく、モジュールロードの機能も提供しています.Angularモジュール管理は、コード論理上のモジュール化をより気にし、グローバル変数汚染を回避し、jsファイルレベルのロード機能を提供しない.論理モジュール管理としては、requirejsのモジュール管理を実用化すれば十分なので、angular原生のcontroller、serviceのほか、ビジネス関連のパブリックライブラリは、requirejsを使いましょう.