angularjs學習筆記——使用requirejs動態注入控制器

最近一段時間在學習angularjs,因爲以爲直接使用它須要加載不少的js文件,所以想使用requirejs來實現異步加載,並動態注入控制器。簡單搜索了下發現好多教程寫的都很複雜,因此打算寫一下個人方法,算是學習筆記了。html

demo目錄以下圖:
目錄結果angularjs

index.html文件的內容:bootstrap

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>demo</title>
    
    <!-- 引入requirejs,並在main.js中初始化 -->
    <script data-main="main.js" src="libs/require.js">
</script>
</head>
<body>
    <div ng-view></div>
</body>
</html>

在引入main.js後,就須要在其中完成requirejs的初始化:數組

// main.js

'use strict';

(function (win) {
    require.config({
        baseUrl: './',
        // 依賴相對路徑
        paths: {               
            'angular': 'libs/angular.min',
            'angular-route': 'libs/angular-route.min'
        },
        // 引入沒有使用requirejs模塊寫法的類庫
        shim: {
            'angular': {
                exports: 'angular'
            },
            'angular-route': {
                // angular-route依賴angular
                deps: ['angular'],
                exports: 'ngRoute'
            }
        }
    });
    
    // 自動導入router.js模塊,因爲後綴名能夠省略,故寫做'router',
    // 並將模塊返回的結果賦予到router中。
    require(['angular','router'], function(angular,router){
        // 手動啓動angularjs,特別說明此處的bootstrap不是那個ui框架,
        // 而是angularjs的一個手動啓動框架的函數
        angular.bootstrap(document, ['blogApp']);
    });
})(window);

main.js中完成了各模塊的初始化,而且引入了router.js
下面咱們在router.js中配置路由:promise

// router.js

define(['angular', 'require', 'angular-route'], function (angular, require) {

    var blogApp = angular.module('blogApp',['ngRoute']);

    blogApp.config(['$routeProvider','$controllerProvider',
        function($routeProvider,$controllerProvider) {
            $routeProvider
            .when('/', {
                templateUrl:'templates/list.html',
                controller: 'ListCtrl',
                resolve:{
                    delay : ctrlRegister('ListCtrl',['controllers/ListCtrl.js'])
                }
            })
            .when('/data', {
                templateUrl:'templates/data.html',
                controller: 'DataCtrl',
                resolve:{
                    delay : ctrlRegister('DataCtrl',['controllers/DataCtrl.js'])
                }
            })
            .otherwise({
                redirectTo: '/'
            });

            function ctrlRegister (ctrlName, ctrlModule) {
                return function ($q) {
                    var defer = $q.defer();
                    require(ctrlModule, function (controller) {

                        $controllerProvider.register(ctrlName, controller);

                        defer.resolve();
                    });
                    return defer.promise;
                }
            }
        }
    ]);

    return blogApp;
});

我把這裏面拆爲分三個部分來講
第一部分:定義該模塊框架

// 引入3個基礎模塊
define(['angular', 'require', 'angular-route'], function (angular, require) {
    
    // 定義整個demo爲一個名爲blogApp的模塊
    var blogApp = angular.module('blogApp',['ngRoute']);
    
    // ...第二部分:路由配置...
    // ...第三部分:複用的動態注入控制器函數
    
    // 向main.js返回這個blogApp
    return blogApp;
});

第二部分:設置基礎路由異步

blogApp.config(['$routeProvider','$controllerProvider',
        function($routeProvider,$controllerProvider) {
            $routeProvider
            .when('/', {
                // 模板地址
                templateUrl:'templates/list.html',
                // 控制器的名字
                controller: 'ListCtrl',
                // resolve用來在完成路由前處理一些事
                // 這裏用來動態加載並注入相應的控制器
                resolve:{
                    // ctrlRegister爲我本身寫的一個複用的函數,
                    // 用於注入控制器。見第三部分
                    delay : ctrlRegister('ListCtrl',['controllers/ListCtrl.js'])
                }
            });
       }
}

第三部分:複用的控制器注入函數ide

// 該函數接受兩個參數
// ctrlName,字符串類型,爲該控制器的名字
// ctrlModule,字符串數組類型,爲要引入的控制器的相對地址
// 調用例如 ctrlRegister('ListCtrl',['controllers/ListCtrl.js'])
function ctrlRegister (ctrlName, ctrlModule) {

    return function ($q) {
        var defer = $q.defer();
        // 加載該控制器,並將返回值賦給controller,返回值通常是一個控制器函數
        require(ctrlModule, function (controller) {
            // 將返回值註冊爲名稱爲ctrlName的控制器
            $controllerProvider.register(ctrlName, controller);

            defer.resolve();
        });
        // 完成註冊
        return defer.promise;
    }
}

好了,這樣就完成了動態加載的功能了,下面就能夠寫要動態加載的控制器了
用其中一個控制器ListCtrl.js來講明問題:函數

// ListCtrl.js

// 加載angular模塊
define(['angular'], function (angular) {
    將本控制器函數做爲結果返回給router.js
    return function ListCtrl( $scope ){
        $scope.lists = ['1','2','3'];
    };
});

剩下的事情就是在list.html中接收控制器傳送的數據了:requirejs

<!-- list.html -->
<ul>
    <li ng-repeat="list in lists"><a href="#/{{list}}" ng-bind="list"></a></li>
</ul>

最終實現的功能是:
好比我訪問http://127.0.0.1/demo/#/只會加載list.htmlListCtrl.js
而當訪問http://127.0.0.1/demo/#/data就只會加載data.htmlDataCtrl.js。這樣作有什麼好處呢?當有不少控制器時,能夠按需加載相應的控制器,不會一股腦所有加載上來(看起來依然並無什麼卵用)。很慚愧,只爲你們節約了一點微小的帶寬,謝謝你們。

相關文章
相關標籤/搜索