概览
这篇文档描述了AngularJS的主要组成部分,以及它们如何协同工作。它们是:
- 启动(startup)- 展示“hello world!”
- 执行期(runtime)- AngularJS 执行期概览
- 作用域(scope)- 视图和控制器的集合区
- 控制器(controller)- 应用的行为
- 模型(model)- 应用的数据
- 视图(view)- 用户能看到的
- 指令(directives)- 扩展HTML语法
- 过滤器(filters)- 数据本地化
- 注入器(injector)- 聚合你的应用
- 模块(module)- 配置注入器
- $- AngularJS的命名空间(namespace)
启动
下面解释了我们是如何把这一切运转起来的(用一张图和一个例子来解释):
- 浏览器载入HTML,然后把它解析成DOM。
- 浏览器载入angular.js脚本。
- AngularJS等到
DOMContentLoaded
事件触发。 - AngularJS寻找
ng-app
指令,这个指令指示了应用的边界。 - 使用
ng-app
中指定的模块来配置注入器($injector)。 - 注入器($injector)是用来创建“编译服务($compile service)”和“根作用域($rootScope)”的。
- 编译服务($compile service)是用来编译DOM并把它链接到根作用域($rootScope)的。
ng-init
指令将“World”赋给作用域里的name这个变量。- 通过
{{name}}
的替换,整个表达式变成了“Hello World”。
index.html:
<!doctype html> <html ng-app><head><scriptsrc="http://code.angularjs.org/angular-1.1.0.min.js"></script></head><body><png-init" name='World' "Hello {{name}}!</p></body></html>运行效果
控制器
视图背后的控制代码就是控制器。它的主要工作内容是构造模型,并把模型和回调方法一起发送到视图。 视图可以看做是作用域在模板(HTML)上的“投影(projection)”。而作用域是一个中间地带,它把模型整理好传递给视图,把浏览器事件传递给控制器。控制器和模型的分离非常重要,因为:
- 控制器是由Javascript写的。Javascript是命令式的,命令式的语言适合用来编写应用的行为。控制器不应该包含任何关于渲染代码(DOM引用或者片段)。
- 视图模板是用HTML写的。HTML是声明是的,声明式的语言适合用来编写UI。视图不应该包含任何行为。
- 因为控制器和视图没有直接的调用关系,所以可以使多个视图对应同一个控制器。这对“换肤(re-skinning)”、适配不同设备(比如移动设备和台式机)、测试,都非常重要。
"MyCtrl"<buttonng-click"action()" OK </button> script.js:
MyCtrlaction function()'OK' 模型模型就是用来和模板结合生成视图的数据。模型必须在作用域中时可以被引用,这样才能被渲染生成视图。和其他框架不一样的是,Angularjs对模型本身没有任何限制和要求。你不需要继承任何类也不需要实现指定的方法以供调用或者改变模型。 模型可以是原生的对象哈希形式的,也可以是完整对象类型的。简而言之,模型可以是原生的Javascript对象。
视图
所谓视图,就是指用户所看见的。 视图的生命周期由作为一个模板开始,它将和模型合并并最终渲染到浏览器的DOM中。与其他模板系统不同的是,AngularJS使用一种独特的形式来渲染视图。
- 其他模板 - 大部分模板系统工作原理,都是一开始获取一个带有特殊标记的HTML形式字符串。通常情况下模板的特殊标记破换了HTML的语法,以至于模板是不能用HTML编辑器编辑的。然后这个字符串会被送到模板引擎那里解析,并和数据合并。合并的结果是一个可以被浏览器解析的HTML字符串。这个字符串会被
.innerHTML
方法写到DOM中。使用innerHTML会造成浏览器的重新渲染。当模型改变时,这整个流程又要重复一遍。模板的生存周期就是DOM的更新周期。这里我想强调是,这些模板系统模板的基础是字符串。- AngularJS - AngularJS和其它模板系统不同。它使用的是DOM而不是字符串。模板仍然是用HTML字符串写的,并且它仍然是HTML。浏览器将它解析成DOM, 然后这个DOM会作为输入传递给模板引擎,也就是我们的编译器。编译器查看其中的指令,找到的指令后,会开始监视指令内容中相应的模型。 这样做,就使得视图能“连续地”更新,不需要模板和数据的重新合并。你的模型也就成了你视图变化的唯一动因。
"list = ['Chrome','Safari','Firefox','IE'] "
"list"ng-list<br><pre>list={{list}}</pre>"item in list" {{item}} 指令一个指令 就是一种“由某个属性、元素名称、css类名出现而导致的行为,或者说是DOM的变化”。指令能让你以一种声明式的方法来扩展HTML表示能力。下面演示了一个增加了数据绑定的“内容可编辑”HTML。
ng-app
"directive"contentEditable"true""content"Edit Memodel = {{content}} script.js:style.css:// always true because of instance cache===);div[contentEditable] cursor pointer backgroundcolor #D0D0D0;bottom1em padding Filters过滤器过滤器扮演着数据翻译的角色。一般他们主要用在数据需要格式化成本地格式的时候。它参照了UNIX过滤的规则,并且也实现了“|”(管道)语法。
Number formatting: {{ 1234567890 | number }}
array filtering "predicate" {{ list | filter:predicate | json }} 模块和注入器每个AngularJS应用都有一个唯一的注入器。注入器提供一个通过名字查找对象实例的方法。它将所有对象缓存在内部,所以如果重复调用同一名称的对象,每次调用都会得到同一个实例。如果调用的对象不存在,那么注入器就会让实例工厂(instance factory)创建一个新的实例。
一个模块就是一种配置注入器实例工厂的方式,我们也称为“提供者(provider)”。
// Create a modulevar myModule angular.module('myModule'[])// Configure the injector myModulefactory'serviceA'@H_301_154@return// instead of {},put your object creation here};});// create an injector and configure it from 'myModule' $injector injector);// retrieve an object from the injector by name serviceA $injector@H_301_154@get
注入器真正强大之处在于它可以用来调用方法和实例化的类型。这个精妙的特性让方法和类型能够通过注入器请求到他们依赖的组件,而不需要自己加载依赖。
// You write functions such as this one. doSomethingserviceA serviceB// do something here.// Angular provides the injector for your application...;///////////////////////////////////////////////// the old-school way of getting dependencies. serviceB 'serviceB'// now call the function// the cool way of getting dependencies.// the $injector will supply the arguments to the function automaticallyinvokedoSomething// This is how the framework calls your functions
注意,你唯一需要写的就是上例中指出的函数,并把需要的依赖写在函数参数里。当AngularJS调用这个函数时,它会自动体充好需要的参数。
看看下面的动态时间的例子,注意它是如何在构造器中列举出依赖的。当ng-controller
实例化构造器的时候,它自动提供了指明的依赖。没有必要去创建依赖、查找依赖、或者提供一个依赖的引用给注入器。
"timeExampleModule""ClockCtrl" Current time is: {{ time.now }} angular'timeExampleModule'[]).// Declare new object call time,174); font-style:italic">// which will be available for injection factory'time'$timeout time {};( tick timenow @H_301_154@newDate().toString(); $timeouttick1000})();// Notice that you can simply ask for time// and it will be provided. No need to look for it.ClockCtrltime AngularJS 命名空间
为了防止意外的命名冲突, AngularJS为可能冲突的对象名加以前缀"$"。所以请不要在你自己的代码里用"$"做前缀,以免和AngularJS代码发生冲突。