最近一直在看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(); } }