最近一直在看angularjs的一些東西,因為項目的需要所以開始着手學習什么是angularjs。下面簡單的記錄一下angularjs的啟動,來看看這個框架是如何啟動工作的。
我們在做簡單的測試的時候通過下面的代碼可以實現一個雙向數據綁定的小例子:

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script src="libs/angular.js/1.4.6/angular.min.js"></script> </head> <body> <div ng-app=""> <p>名字 : <input type="text" ng-model="name"></p> <h1>Hello {{name}}</h1> </div> </body> </html>
從代碼中我們知道<div ng-app="">這個地方的ng-app並沒有給賦值,這個時候我們的代碼是可以正常調用起來的。
我們試着去給ng-app賦值,暫且叫做myapp

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script> </head> <body> <div ng-app="myapp"> <p>名字 : <input type="text" ng-model="name"></p> <h1>Hello {{name}}</h1> </div> </body> </html>
這個時候我們發現出現了無法解析表達式的界面
於是我們猜想,是不是框架里不賦值的時候框架會自動的加載啟動angularjs呢,而當我們真正的給它一個名字的時候我們需要手工的給它啟動。
然而當我們加上var myapp= angular.module("myapp",[]); 這句初期化的語句的時候,我們發現程序又可以正常的啟動了。顯然猜測是錯誤的。
翻看源碼后發現angularjs的源碼里有一個叫做bootstrap()的方法,原來這就是啟動angularjs的方法。根據這個方法我們總結如下:
第一種情況:當頁面元素中有ng-app或者是ng-app=""的時候,angularjs是可以自動啟動的。
第二種情況:當頁面中的ng-app元素的內容被定義以后,我們可以通過var myapp= angular.module("myapp",[]);這種形式對它進行初期化,之后也是可以正常啟動的。
第三種情況:當頁面中沒有ng-app元素的時候,這個時候我們需要手動的啟動angularjs了。手工啟動的方法如下:

<script> var myapp= angular.module("myapp",[]); angular.element(document).ready(function(){ angular.bootstrap(document,['myapp']); }); </script>
第四種情況:當頁面中出現多個ng-app元素的時候,通常只會認識第一個元素,也很少有人會在一個html頁面里定義兩個ng-app,但是如果非要定義兩個也可以采用第三種的方式手動啟動第二個ng-app的入口。(當然正常的開發過程中沒有人會這樣給自己找麻煩的,顯然把ng-app放到最外層,內容的業務交互完全可以交給Controller去處理)
綜上所述,我們明白了,原來在angularjs的啟動過程中真正的門是一個叫做bootstrap的方法,var myapp= angular.module("myapp",[]);只是做個初期化並不是真正的啟動方法。
后面附上部分源碼共參考

function angularInit(element, bootstrap) {
var appElement,
module,
config = {};
// The element `element` has priority over any other element
forEach(ngAttrPrefixes, function(prefix) {
var name = prefix + 'app';
if (!appElement && element.hasAttribute && element.hasAttribute(name)) {
appElement = element;
module = element.getAttribute(name);
}
});
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);
}
}

function bootstrap(element, modules, config) { if (!isObject(config)) config = {}; var defaultConfig = { strictDi: false }; config = extend(defaultConfig, config); var doBootstrap = function() { element = jqLite(element); if (element.injector()) { var tag = (element[0] === window.document) ? 'document' : startingTag(element); //Encode angle brackets to prevent input from being sanitized to empty string #8683 throw ngMinErr( 'btstrpd', "App already bootstrapped with this element '{0}'", tag.replace(/</,'<').replace(/>/,'>')); } modules = modules || []; modules.unshift(['$provide', function($provide) { $provide.value('$rootElement', element); }]); if (config.debugInfoEnabled) { // Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`. modules.push(['$compileProvider', function($compileProvider) { $compileProvider.debugInfoEnabled(true); }]); } modules.unshift('ng'); var injector = createInjector(modules, config.strictDi); injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', function bootstrapApply(scope, element, compile, injector) { scope.$apply(function() { element.data('$injector', injector); compile(element)(scope); }); }] ); return injector; }; var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/; var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/; if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) { config.debugInfoEnabled = true; window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, ''); } if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) { return doBootstrap(); } window.name = window.name.replace(NG_DEFER_BOOTSTRAP, ''); angular.resumeBootstrap = function(extraModules) { forEach(extraModules, function(module) { modules.push(module); }); return doBootstrap(); }; if (isFunction(angular.resumeDeferredBootstrap)) { angular.resumeDeferredBootstrap(); } }