angularJS+ui-router+requireJS異步加載controller、directive、filter

開發比較複雜的單頁面應用時,往往包括比較多的控制器、服務等,如果這些js文件都在頁面打開時就全部加載,往往加載量大,耗時長;因此,當打開對應的頁面才加載響應的控制器等資源時,能一定程度地優化頁面加載速度。

· 項目目錄結構:
這裏寫圖片描述

· index.html:

<html>
    <head>
        <title></title>
    </head>
    <body>
        <div ui-view></div>
        <script type="text/javascript" src="js/libs/require.js" data-main="js/main"></script>
    </body>
</html>

· main.js

require.config({
    baseUrl: 'js',
    paths: {
        'app': 'app',
        'angular': 'libs/angular.min',
        'router': 'libs/angular-ui-router'
    },
    shim: {
        'angular': {
            exports: 'angular'
        },
        'router': {
            deps: ['angular']
        },
        'app': {
            deps: ['router']
        }
    }
})
// 手動初始化myModule模塊
require(['app'],function(){
    angular.bootstrap(document, ['myModule'])       
})

在main.js中配置文件路徑,初始化模塊。此處使用angular.bootstrap完成模塊的手動加載

· 各模塊視圖
先來看一下views中包含的文件:
這裏寫圖片描述
home文件夾裏的是每一個視圖都包含的相同的視圖部分,比如PC網站每一個頁面都有相同的導航欄,底部版權信息,這類視圖分塊就可以單獨抽出來,再在app.js中嵌套到路由中。

../home/index.html:

<!--主模塊結構-->
<div class="container">
    <div ui-view="topbar"></div>
    <div ui-view="main"></div>
    <div ui-view="footer"></div>
</div>

../home/topbar.html:

<a ui-sref="index">首頁</a>
<a ui-sref="index.news">資訊動態</a>
<a ui-sref="index.community">社區科普</a>
<a ui-sref="index.resource">科普資源</a>
<a ui-sref="index.signin">活動報名</a>
<a ui-sref="index.learn">在線學習</a>
<a ui-sref="index.notice">通知公告</a>
<a ui-sref="index.service">志願者服務</a>
<a ui-sref="index.about">關於我們</a>

· app.js

define(['angular','router'],function(){
    var app = angular.module("myModule", ['ui.router'])
    app.config(function($controllerProvider,$compileProvider,$filterProvider,$provide){     
        app.register = {
            //得到$controllerProvider的引用
            controller : $controllerProvider.register,
            //同樣的,這裏也可以保存directive/filter/service的引用
            directive: $compileProvider.directive,
            filter: $filterProvider.register,
            service: $provide.service
        };
    })
.config(['$stateProvider','$urlRouterProvider',function($stateProvider, $urlRouterProvider){
    $urlRouterProvider.otherwise('/index');
    $stateProvider
    .state("index",{
        url:"/index",
        views: {
                '': {
                    templateUrl: 'views/home/index.html'
                },
                'topbar@index': {
                    templateUrl: 'views/home/topbar.html'
                },
                'main@index': {
                    templateUrl: 'views/home/home.html'
                },
                'footer@index': {
                    templateUrl: 'views/home/footer.html'
                }
            }
    })
    // 模塊1
    .state("index.news",{
        url:"/news",       
        views: {
                'main@index': {
                    templateUrl: 'views/modules/news/news.html',
                    controller: 'newsCtrl',
                    resolve: {
                        loadCtrl: ["$q", function($q) { 
                            var deferred = $q.defer();
                            //異步加載controller/directive/filter/service
                            require([
                                'directives/myDirective',
                                'filters/sexFilter',
                                'controller/newsCtrl'
                                ], function() { deferred.resolve(); });
                             return deferred.promise;
                        }]
                    },
                }
            }
    })    
    // 模塊2
    .state("index.about",{
        url:"/about",
        views: {
                'main@index': {
                    templateUrl: 'views/modules/about/about.html',
                    controller: 'aboutCtrl',
                    resolve: {
                        loadCtrl: ["$q", function($q) { 
                            var deferred = $q.defer();
                            //異步加載controller/directive/filter/service
                            require([
                                'controller/aboutCtrl'
                            ], function() { deferred.resolve(); });
                            return deferred.promise;
                        }]
                    }                     
                }
            },
    })       
}])
    return app;
})

此處使用了路由嵌套,由於views可能包含多個視圖,所以對應視圖的controller記得寫在響應的視圖定義區域內噢。

· newsService.js:

define(['app'],function(app){
    //Service比較特殊,加載後還需要手動注入控制器
    app.register.service('newsService', function($http, $q){
        return {
            getData:function(){
                var deferred = $q.defer();
                var promise = $http.get("/json/news.json");
                promise.then(
                    // 通訊成功的處理
                    function(answer){
                        //在這裏可以對返回的數據集做一定的處理,再交由controller進行處理
                        answer.status = true;
                        deferred.resolve(answer);
                    },
                    // 通訊失敗的處理
                    function(error){
                        // 可以先對失敗的數據集做處理,再交由controller進行處理
                        error.status = false;
                        deferred.reject(error);
                        console.log("獲取資訊動態數據失敗");
                    });
                //返回promise對象,交由controller繼續處理成功、失敗的業務回調
                return deferred.promise;
            }
        }
    })
})

· newsCtrl.js:

define(['app','service/newsService'],function(app){
    // 控制器 將服務器手動注入控制器中
    app.register.controller('newsCtrl', function($scope,newsService){
        newsService.getData().then(
            function(answer){
                $scope.newsList = answer.data;
            },
            function(error){
                $scope.error = error;
            }
        );        
    });
});

自定義指令以及過濾器的寫法也類似噢~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章