最近一段时间在学习angularjs
,由于觉得直接使用它需要加载很多的js文件,因此想使用requirejs
来实现异步加载,并动态注入控制器。简单搜索了下发现好多教程写的都很复杂,所以打算写一下我的方法,算是学习笔记了。
demo目录如下图:
- <!-- 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
中配置路由:
- // 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) {
- // 定义整个demo为一个名为blogApp的模块
- var blogApp = angular.module('blogApp',['ngRoute']);
- // ...第二部分:路由配置...
- // ...第三部分:复用的动态注入控制器函数
- // 向main.js返回这个blogApp
- return blogApp;
- });
第二部分:设置基础路由
- blogApp.config(['$routeProvider',{
- // 模板地址
- templateUrl:'templates/list.html',// 控制器的名字
- controller: 'ListCtrl',// resolve用来在完成路由前处理一些事
- // 这里用来动态加载并注入相应的控制器
- resolve:{
- // ctrlRegister为我自己写的一个复用的函数,
- // 用于注入控制器。见第三部分
- delay : ctrlRegister('ListCtrl',['controllers/ListCtrl.js'])
- }
- });
- }
- }
第三部分:复用的控制器注入函数
- // 该函数接受两个参数
- // 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
中接收控制器传送的数据了:
- <!-- 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.html
和ListCtrl.js
;
而当访问http://127.0.0.1/demo/#/data
就只会加载data.html
和DataCtrl.js
。这样做有什么好处呢?当有很多控制器时,可以按需加载相应的控制器,不会一股脑全部加载上来(看起来依然并没有什么卵用)。很惭愧,只为大家节约了一点微小的带宽,谢谢大家。