CUF_meeting_knowledge_share
CUF_meeting_knowledge_share copied to clipboard
2014-12-8 AngularJS 执行流程 | 如何使用RequireJS管理AngularJS和Dojo
AngularJS 执行流程
首先感谢慕课网提供的阿里懒懒交流会的视频,本人是受益匪浅的,这次主要是想分享由城池同学分享的AngularJS执行流程的视频
通过对AngularJS源码(基于AngularJS v1.3.3源码)的分析,将AngularJS执行流程分为三大块:
- bindJQuery
- publishExternalAPI
- angularInit
//AngularJS源码25741 - 25747行
bindJQuery();
publishExternalAPI(angular);
jqLite(document).ready(function() {
angularInit(document, bootstrap);
bindJQuery
判断是否引入JQuery,如果没有就内置JQlite(对JQuery的轻量级实现)
publishExternalAPI
- 挂载常用API,如:bootstrap,forEach等方法(源码2111行 -- 2142行)
- 将nglocate挂载到angular.module上 (源码2146行)
- 将ng挂载到angular.module上 (源码2151行)
- 注意源码2144行 setupModuleLoader方法 如何实现挂载module,该方法在源码1665行注意该方法返回的对象,这个是angularjs实现链式操作的关键
//源码1952 return moduleInstance
var moduleInstance = {
// Private state
_invokeQueue: invokeQueue,
_configBlocks: configBlocks,
_runBlocks: runBlocks,
requires: requires,
name: name,
provider: invokeLater('$provide', 'provider'),
factory: invokeLater('$provide', 'factory'),
service: invokeLater('$provide', 'service'),
value: invokeLater('$provide', 'value'),
constant: invokeLater('$provide', 'constant', 'unshift'),
animation: invokeLater('$animateProvider', 'register'),
filter: invokeLater('$filterProvider', 'register'),
controller: invokeLater('$controllerProvider', 'register'),
directive: invokeLater('$compileProvider', 'directive'),
config: config,
... ...
angularInit
- 通过ng-app="xx",取出moduleName (源码1324行)
- bootstrap(appElement, [module]) (源码1403行)
- createInjector (源码1434行) 实现依赖注入
createInjector(modules)
//经所有provider存放在这里
provideCache: {$provider, $injector}
//如果调用过,存在这里
instanceCache: {$injector}

如何使用RequireJS管理AngularJS和Dojo
前端代码规模越来越大,为了更好的组织和管理前端代码,需要进行模块化和解耦合,提高代码的可扩展性和可维护性,AngularJS充分满足我们的需求,Angular具有模块化,MVC,双向数据绑定和指令系统四大特性,但是它的UI相对较弱,所以当项目使用AngularJS作为核心时,需要引入其他库对其UI进行增强(将dojo UI组件封装成AngularJS的指令),在这里我们选用dojo,选用dojo原因是dojo本身就是AMD模块化库,可以与RequireJS无缝集成,另外它的组件丰富且功能强大。
基于以上观点,决定选用RequireJS来管理AngularJS和Dojo,首先先明确一点,AngularJS虽然是模块化库,但是它不是AMD模块化,所以需要在RequireJS中进行特殊配置。
/**
* Created by hjzheng on 2014/12/4.
* This is a require config file
*/
require.config({
baseUrl: "./",
//dojo and dijit are AMD module, so you can easy to use require to load them
paths: {
'dojo': 'bower_components/dojo',
'dijit': 'bower_components/dijit',
'angular': 'bower_components/angular/angular',
'angular-route': 'bower_components/angular-route/angular-route',
'domReady': 'bower_components/domReady/domReady'
},
//angular does not support AMD out of the box, put it in a shim
shim: {
'angular': {
exports: 'angular'
},
'angular-route': {
deps: ['angular'],
exports: 'angular-route'
}
},
// kick start application
deps: ['./js/bootstrap']
});
对AngularJS进行特殊配置后,需要手动启动AngularJS
/**
* Created by hjzheng on 2014/12/4.
* The whole project bootstrap by Angularjs
*/
define([
'require',
'angular',
'./route',
'./app'
], function (require, ng) {
require(['domReady!'], function (document) {
ng.bootstrap(document, ['app']);
});
});
其它更多细节,大家自己参考我的项目 https://github.com/hjzheng/RequireJS-Dojo-AngularJS
在这里举一个简单的封装dijit/form/Button的简单例子
/**
* Created by hjzheng on 2014/12/4.
* This file define directive my-button
* use dijit/form/Button
*/
define(['./module', 'dijit/form/Button'], function (directives, Button) {
directives.directive('myButton', function () {
return {
restrict: 'EA',
template: '<div></div>',
replace: true,
scope: {
label: "@"
},
link: function ($scope, iElm, iAttrs, controller) {
new Button({
label: $scope.label,
onClick: function () {
console.log("click dojo button");
}
}, iElm[0]).startup();
}
};
});
});