angularjs教程

AngularJS框架研究(一)

时间:2015-07-12 10:55来源:网络整理 作者:KKWL 点击:
//try to bind to jquery now so that one can write angular.element().read() //but we will rebind on bootstrap again. bindJQuery();publishExternalAPI(angular); jqLite(document).ready(function() {angularInit(document, bootstrap); }); })(window

//try to bind to jquery now so that one can write angular.element().read() //but we will rebind on bootstrap again. bindJQuery(); publishExternalAPI(angular); jqLite(document).ready(function() { angularInit(document, bootstrap); }); })(window, document);

红色部分标出的正是AngularJS的入口。AngularJS内置了jQuery的轻量版本jqLite,具体代码见src/jqLite.js。bindJquery函数会尝试去绑定jQuery库,如果没有找到,就用内置的jqLite。DOM加载完毕后,执行angularInit函数,作准备工作。

function angularInit(element, bootstrap) { var elements = [element], appElement, module, names = ['ng:app', 'ng-app', 'x-ng-app', 'data-ng-app'], NG_APP_CLASS_REGEXP = /\sng[:\-]app(:\s*([\w\d_]+);?)?\s/; function append(element) { element && elements.push(element); } forEach(names, function(name) { names[name] = true; append(document.getElementById(name)); name = name.replace(':', '\\:'); if (element.querySelectorAll) { forEach(element.querySelectorAll('.' + name), append); forEach(element.querySelectorAll('.' + name + '\\:'), append); forEach(element.querySelectorAll('[' + name + ']'), append); } }); forEach(elements, function(element) { if (!appElement) { var className = ' ' + element.className + ' '; var match = NG_APP_CLASS_REGEXP.exec(className); if (match) { appElement = element; module = (match[2] || '').replace(/\s+/g, ','); } else { forEach(element.attributes, function(attr) { if (!appElement && names[attr.name]) { appElement = element; module = attr.value; } }); } } }); if (appElement) { bootstrap(appElement, module ? [module] : []); } }

angularInit函数主要用来寻找主程序入口。如果在DOM中找到了ng-app标记,则调用bootstrap开始初始化框架。如果没有定义app标记,则需要手动调用angular.bootstrap来初始化。app标记一般在html节点,也可以放置在任意的节点上,app节点所在的DOM树都会被AngularJS框架遍历解析。

ng-app属性如果有值,即自定义module,也会被解析出来,前提是我们必须先创建module,用来管理全局的injector行为和对象。如果没有值,则会创建默认的module。

function bootstrap(element, modules) { var doBootstrap = function() { element = jqLite(element); if (element.injector()) { var tag = (element[0] === document) ? 'document' : startingTag(element); throw ngMinErr('btstrpd', "App Already Bootstrapped with this Element '{0}'", tag); } modules = modules || []; modules.unshift(['$provide', function($provide) { $provide.value('$rootElement', element); }]); modules.unshift('ng'); var injector = createInjector(modules); injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', '$animate', function(scope, element, compile, injector, animate) { scope.$apply(function() { element.data('$injector', injector); compile(element)(scope); }); animate.enabled(true); }] ); return injector; }; var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/; 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); }); doBootstrap(); }; }

按照官方文档描述,bootstrap步骤分为三步:首先加载module,然后创建全局injector对象,最后执行compile动作,对应的正是上面的代码。

AngularJS会为每个应用程序创建唯一的injector对象,它可以看作是一个对象池,依靠键值来存取实例,比如存放数据的model,和后端交互的service等,而实例的创建则由module来决定。

在AngularJS框架中,应用程序被看作是由多个module组成的一个结合体,而一个module,往往是相似功能块的组合。在一个大型应用程序中,我们习惯将程序切分为多个模块并行开发,这也是AngularJS的推荐做法。在module中,可以定义和View层打交道的Controller,和后台交互的Service,也可以自定义依赖注入行为,解析特殊的DOM数据。

从上面的代码可以看到,初始化时会加载内置的模块,比如“ng”。在ng模块中定义了AngularJS的核心功能,包括解析DOM树中的以“ng”为前缀的自定义节点, 比如ng-model,ng-class,ng-repeat等等。

compile,编译,顾名思义,就是将DOM中的ng标记和其他自定义标记解析为真正的View, Model和Controller等。

--------------------

到这里为止,对AngularJS的运行机制还处于一知半解,不得不吐槽下,想要弄懂AngularJS的运行机制实在不是件容易的事。

最后再补充一点:有一款名为"Batarang"的Chrome扩展插件一定不能错过,AngularJS开发调试必备。用过后,才知道官网上一些截图是怎么来的了~

------分隔线----------------------------