AngularJS的源码在整体上,与其它很多库和框架一样,是一个自执行函数,其整体结构简化如下:
(function(window, document, undefined) {
if (window.angular.bootstrap) {//判断是否已经启动
console.log('WARNING: Tried to load angular more than once.');
return;
}
bindJQuery();//绑定JQuery
publishExternalAPI(angular);//对外公布AngularJS的函数
jqLite(document).ready(function() {
angularInit(document, bootstrap);//启动AngularJS
});
})(window, document);
整体思路
该方法主要是绑定jQuery,简化后的代码如下:
var bindJQueryFired = false;
function bindJQuery() {
if (bindJQueryFired) {
return;
}
var jqName = jq();
jQuery = window.jQuery;
if (isDefined(jqName)) {
jQuery = jqName === null ? undefined : window[jqName];
}
if (jQuery && jQuery.fn.on) {
jqLite = jQuery;
// ... ...
} else {
jqLite = JQLite;
}
angular.element = jqLite;//具体意义看脚注
bindJQueryFired = true;
}
查看angular.element1
总结起来,绑定的jQuery可以的来源有三个:ng-jq指定、引入的jQuery库、内置实现的JQLite,其使用流程为:
该方法的代码简化如下:
function publishExternalAPI(angular) {
//拓展angular对象
extend(angular, {
......
});
//定义angular.module方法
angularModule = setupModuleLoader(window);
//尝试获取ngLocal模块,如果没有,则需要注册一个
try {
angularModule('ngLocale');
} catch (e) {
angularModule('ngLocale', []).provider('$locale', $LocaleProvider);
}
//注册ng模块,也就是angularJS的核心模块
angularModule('ng', ['ngLocale'], ['$provide',
function ngModule($provide) {
// ... ...
}
]);
}
主要功能为:
function angularInit(element, bootstrap) {
var appElement,
module,
config = {};
//先判断element元素是否包含ng-app属性
forEach(ngAttrPrefixes, function(prefix) {
var name = prefix + 'app';
if (!appElement && element.hasAttribute && element.hasAttribute(name)) {
appElement = element;
module = element.getAttribute(name);
}
});
//再判断element元素的子元素中是否包含ng-app属性
forEach(ngAttrPrefixes, function(prefix) {
var name = prefix + 'app';
var candidate;
if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) {
appElement = candidate;
module = candidate.getAttribute(name);
}
});
if (appElement) {
config.strictDi = getNgAttribute(appElement, "strict-di") !== null;
bootstrap(appElement, module ? [module] : [], config);
}
}
需要说明的是,AngularJS支持的属性前缀有多种,包括ng-、data-ng-、ng:和x-ng-,具体请看ngAttrPrefixes变量。
需要注意的是,如果有多个元素都有ng-app属性,则只会找到第一个并启动它,而后面的应用则不会自动启动。因为这个函数主动执行一次。
应用的启动方式主要包括自动启动和手动启动。
<div ng-app="MyModule">
<div ng-controller="ctrl">
div>
div>
<script>
var myModule = angular.module('MyModule', []);
myModule.controller('ctrl', ['$scope', function($scope) {
$scope.name = 'alex';
}]);
script>
<div>
<div ng-controller="ctrl">
div>
div>
<script>
var myModule = angular.module('MyModule', []);
myModule.controller('ctrl', ['$scope', function($scope) {
$scope.name = 'alex';
}]);
angular.element(document).ready(function() {
angular.bootstrap(document, ['MyModule']);
});
script>
注意 :需要在ready函数中调用启动函数,因为如果文档没有加载完成,则angular无法扫描到含有ng-app标签的元素。