原版地址:http://code.angularjs.org/1.0.2/docs/guide/concepts
继续。。
一、总括
本文主要是angular组件(components)的概览,并说明他们如何工作。列表如下:
- statup - 依旧是hello world...改为Hello Kitty!
- runtime - 介绍angular的runtime
- scope - view与contorller的纽带(神马glue...胶)
- controller - app的行为(application behavior)
- model - app的数据
- view - 用户所看到的东东
- directives - HTML的语法扩展
- filters - 根据用户的本地格式,格式化数据
- injector - 加载我们的app(依赖管理之类)
- module - 配置injector
- $ - angular的命名空间(namespace)
二、启动(Startup)
下面描述angular是如何启动的(参考图表与下面的例子):
1. 浏览器加载HTML,将HTML标签转换为DOM对象;
2. 浏览器加载angular.js的脚本;
3. Angular等待DOMContentLoaded事件;
4. Angular寻找ng-app这个用于指定应用边界范围的directive;
5. 如果ng-app有指定module(也许是ng-app=”SomeApp”),将被用作配置$injector;
6. $injector用于创建$compile服务(service)以及$rootScope;
7. $compile服务用作“编译”(有点像遍历,然后做一点神秘的事情)DOM,并将其与对应的$rootScope连接。
8. ng-init 这个directive在对应的scope中创建name属性并对其赋予”Kitty”值;
9. 将“{{name}}”的值插入(interpolates)到表达式中,最终显示”Hello Kitty!”。
<!DOCTYPE html> <html lang="zh-cn" ng-app> <head> <meta charset="UTF-8"> <title>Hello Kitty!</title> <style type="text/css"> .ng-cloak { display: none; } </style> </head> <body> <div ng-init="name='Kitty'">Hello {{name}}!</div> <script src="../angular-1.0.1.js" type="text/javascript"></script> </body> </html></div>
由于今晚跟别人讨论一些东西,所以进度缓慢。。。又是那句。。。现在已经是夜深了。。。Angular,广告之后见!
==============================================
广告完毕。。。继续
三、Runtime
这图表和后面的例子,描述了angular如何通过浏览器event-loop(所有的时间处理函数,以及timer执行的函数,会排在一个queue结构中,利用一个无限的循环,不断从queue中取出函数来执行,这个就是event-loop。来自http://wiki.nodejs.tw/nodejs_from_scratch/javascript-yunodejs/2-1-event-loop)来进行交互。
1. 浏览器event-loop等待事件到来。事件来自于用户交互(DOM events)、timer事件(setTimeout)、network事件(服务端响应,XHR之类);
2. 事件回调函数开始执行。这里进入javascript上下文(context)。这回调函数可以修改DOM结构。
3. 当回调函数执行完毕后,浏览器退出javascript context,根据DOM的改变来重绘视图。
Angular通过创建自己的事件处理循环(event processing loop),修改了一般的javascript流(flow)。这将Javascript分割成传统的和Angular的执行上下文(execution context)。只要是在Angular execution context 里面执行的操作,都拥有angular data-binding、异常处理(exception handling)、属性监视(property watching)等能力。我们可以通过在javascript使用$apply(),进入Angular execution context。但要记住一点,在大多数(angular的)地方(如controllers、services),处理事件的directive会为你调用$apply。手动调用$apply的场景,一般是当你实现自定义事件处理函数,或者处理第三方库的回调的时候。
1. 通过调用scope.$apply(stimulusFn)进入angular execution context。stimulusFn就是我们想在angular execution context中执行的函数(含scope作为参数)或者angular合法的表达式。
2. Angular执行stimulusFn,这通常会改变应用的状态(application state)。
3. Angular进入$digest loop。这个loop由一个处理$evalAsync queue 和处理$watch list两个更小的循环组成。$digest loop会在model稳定之前保持迭代,即$evalAsync queue为空,而且$watch list没有检测到任何变化。
4. $evalAsync queue被用作安排必须跳出当前堆栈帧(堆栈帧指的是在堆栈中为当前正在运行的函数分配的区域(或空间)。传入的参数、返回地址(当这个函数结束后必须跳转到该返回地址。译注:即主调函数的断点处)以及函数所用的内部存储单元(即函数存储在堆栈上的局部变量)都在堆栈帧中。http://book.51cto.com/art/200804/70915.htm C.1.1 堆栈帧)之外,但在浏览器视图绘制之前的工作。这通常是通过使用setTimeout(0)来实现。但setTimeout(0)这方法,会导致缓慢,或者在每个事件处理完毕后,浏览器绘制视图时,出现视图闪烁(angular有没有去解决这个问题?如何解决?)。
5. $watch list是有可能在最近一次迭代中被修改的表达式的集合。如果(model)发生了改变,那么$watch 函数会被调用,从而达到对特定的DOM重新赋值的目标。
6. 一旦Angular $digest loop 完成了(之前3提到的情况),离开angular和javascript的context后,浏览器紧跟着就会去重绘DOM,以响应变化。
下面解释例子“Hello Kitty”(-_-!)是如何在用户在文本框输入文本时实现数据绑定(data-binding)效果。
1. 编译阶段(compilation phase):
a) ng-model和input directive在<input>中版定keydown事件监听器。
b) {{name}}占位符(interpolation,不知道怎么翻译)(表达式)设置一个$watch以便在name发生改变时有所响应。
2. 执行阶段(runtime phase):
a) 在inut控件中按下”X”按钮,让浏览器触发一个keydown事件;
b) input directive捕捉到文本框值的改变,然后调用$apply(“name = ‘X';”),在angular execution context中更新应用的model。
c) Angluar将 “name = ‘X';”应用在model中。(model发生改变)
d) $digest loop开始
e) $watch list检测到name的值被改变了,然后再次解析{{name}}表达式,然后更新DOM。
f) Angulart退出(angular) execution context,再依次退出keydown事件以及javascript execution context;
g) 浏览器重绘视图,更新字符。
<!DOCTYPE html> <html lang="zh-cn" ng-app> <head> <meta charset="UTF-8"> <title>Hello Kitty!</title> <style type="text/css"> .ng-cloak { display: none; } </style> </head> <body> <input ng-model="name" class="ng-cloak"/> <p>Hello {{name}}!</p> <script src="../angular-1.0.1.js" type="text/javascript"></script> </body> </html></div>
四、Scope
scope的是负责检测model的变化,并作为表达式的执行上下文(execution context)。Scope是在一个类似于DOM结构的层次结构中嵌套的(据之前了解,划分可能跟controller有关)。(详情查看individual directive documentation,看看哪个directive会创建新的scope)
下面的例子展示”name”这个表达式的值是根据它依赖(所属)的scope决定的,而且还包含了值查找的方式(类似Js的作用域链,自己没有就找老爸要)。
<!DOCTYPE HTML> <html lang="zh-cn" ng-app> <head> <meta charset="UTF-8"> <title>scope</title> <style type="text/css"> .ng-cloak { display: none; } </style> </head> <body> <div class="ng-cloak" ng-controller="ControllerA"> Hello {{name}}!; </div> <div class="ng-cloak" ng-controller="ControllerB"> Hello {{name}}!; <div class="ng-cloak" ng-controller="ControllerC"> Hello {{name}}!; <div class="ng-cloak" ng-controller="ControllerD"> Hello {{name}}!; </div> </div> </div> <script src="../angular-1.0.1.js" type="text/javascript"></script> <script type="text/j