AngularJS的主要组成部分是:

  • 启动(startup) - 展示“hello world!”
  • 执行期(runtime) - AngularJS 执行期概览
  • 作用域(scope) - 视图和控制器的集合区
  • 控制器(controller) - 应用的行为
  • 模型(model) - 应用的数据
  • 视图(view) - 用户能看到的
  • 指令(directives) - 扩展HTML语法
  • 过滤器(filters) - 数据本地化
  • 注入器(injector) - 聚合你的应用
  • 模块(module) - 配置注入器
  • $ - AngularJS的命名空间(namespace)

启动

我们通过一个例子来讲解启动这个部分

<!doctype html>
<html ng-app>
<head>
<script src="http://code.angularjs.org/angular-1.1.0.min.js"></script>
</head>
<body>
<p ng-init=" name='World' ">Hello {{name}}!</p>
</body>
</html>
  1. 浏览器载入HTML,然后把它解析成DOM树。
  2. 浏览器载入angular.js脚本。
  3. AngularJS等到DOMContentLoaded事件触发执行。
  4. AngularJS寻找ng-app指令,这个指令指示了应用程序的边界。
  5. 使用ng-app中指定的模块来配置注入器($injector)。
  6. 注入器($injector)是用来创建“编译服务($compile service)”和“根作用域($rootScope)”的。
  7. 编译服务($compile service)是用来编译DOM树并把它链接到根作用域($rootScope)的,这里的根作用域就是html。
  8. ng-init指令将“World”赋给作用域里的name这个变量。
  9. 作用域中的name与页面上的{{name}}绑定,整个表达式变成了“Hello World”。

执行期

浏览器的事件机制:

  1. 浏览器的Event loop等待事件的触发。所谓事件包括用户的交互操作、定时事件、或者网络事件(服务器的响应)。
  2. 事件触发后,如果有绑定事件回调函数,那么此函数就会被执行。此时会进入Javascript上下文。通常回调用来修改DOM结构。
  3. 一旦回调执行完毕,浏览器就会离开Javascript上下文,并且根据DOM的修改重新渲染视图。

而AngularJS通过使用自己的Event loop,改变了传统的Javascript工作流。这使得Javascript的执行被分成原生部分和拥有AngularJS执行上下文的部分。只有在AngularJS执行上下文中运行的操作,才能享受到AngularJS提供的数据绑定,异常处理,资源管理等功能和服务。你可以使用 $apply()方法,从普通Javascript上下文进入AngularJS执行上下文。记住,大部分情况下(如在控制器,服务中),$apply都已经被执行过了。只有当你使用自定义的事件回调或者是使用第三方类库的回调时,才需要自己执行$apply。

下面通过一个例子来讲解如何实现“将用户输入绑定到视图上”的效果。

<!doctype html>
<html ng-app>
<head>
<script src="http://code.angularjs.org/angular-1.1.0.min.js"></script>
</head>
<body>
<input ng-model="name">
<p>Hello {{name}}!</p>
</body>
</html>

在编译阶段:
  input元素上的ng-model指令会给<input>输入框绑定keydown事件;
  {{name}}这个变量替换表达式建立了一个 $watch ,来接受 name 变量改变的通知。
在执行期阶段:
  按下任何一个键(以X键为例),都会触发一个 input 输入框的keydown事件;
  input 上的指令捕捉到 input 内容的改变,然后调用 $apply("name = 'X';")来更新处于AngularJS执行上下文中的模型;
  AngularJS将 name='X'应用到模型上;
  $digest 循环开始;这个循环是由两个小循环组成的,这两个小循环用来处理$evalAsync队列和$watch列表。这个$digest循环直到模型“稳定”前会一直迭代。这个稳定具体指的是$evalAsync列表为空,并且$watch列表中检测不到任何改变了。这个$evalAsync队列是用来管理那些“视图渲染前需要在当前栈外执行的操作”。这通常使用 setTimeout(0)来完成的。并且,因为浏览器会根据事件队列按顺序渲染视图,这时还会造成视图的抖动。$watch列表是一个表达式的集合,这些表达式可能是自上次迭代后发生了改变的。如果检测到了有改变,那么$watch函数就会被调用,它通常会把新的值更新到DOM中。

  $watch 列表检测到了name值的变化,然后通知 {{name}}变量替换的表达式,这个表达式负责将DOM进行更新;
  AngularJS退出执行上下文,然后退出Javascript上下文中的keydown事件;
  浏览器以更新的文本重新渲染视图。

作用域(Scope)

作用域是用来检测模型的改变和为表达式提供执行上下文的。它是分层组织起来的,并且层级关系是紧跟着DOM的结构的。

下面这个例子演示了{{name}}表达式在不同的作用域下被解析成了不同的值

<!doctype html>
<html ng-app>
<head>
<script src="http://code.angularjs.org/angular-1.1.0.min.js"></script>
<script>
function GreetCtrl($scope) {
      $scope.name = 'World';
     }      function ListCtrl($scope) {
      $scope.names = ['Igor', 'Misko', 'Vojta'];
     }
</script>
</head>
<body>
<div ng-controller="GreetCtrl">
Hello {{name}}!
</div>
<div ng-controller="ListCtrl">
<ol>
<li ng-repeat="name in names">{{name}}</li>
</ol>
</div>
</body>
</html>

在GreetCtrl控制器中的name等于'World'。在ListCtrl控制器中的name等于'Igor', 'Misko', 'Vojta'。因为它们的作用域不一样。

控制器

视图背后的控制代码就是控制器。它的主要工作内容是构造模型和回调方法,并把模型和回调方法一起发送到视图。 视图可以看做是作用域在模板(HTML)上的投影。而作用域是一个中间地带,它把模型整理好传递给视图,把浏览器事件传递给控制器。控制器和视图的分离非常重要,因为:

(1)控制器是由Javascript写的。Javascript是命令式的,命令式的语言适合用来编写应用的行为。控制器不应该包含任何关于渲染代码(DOM引用或者片段)。
(2)视图模板是用HTML写的。HTML是声明是的,声明式的语言适合用来编写UI。视图不应该包含任何行为。
(3)因为控制器和视图没有直接的调用关系,所以可以使多个视图对应同一个控制器。这对“换肤(re-skinning)”、适配不同设备(比如移动设备和台式机)、测试,都非常重要。

模型

模型就是用来和模板结合生成视图的数据。模型在作用域中可以被引用,这样才能被渲染生成视图。和其他框架不一样的是,Angularjs对模型本身没有任何限制和要求。你不需要继承任何类也不需要实现指定的方法。 模型可以是哈希形式的原生对象,也可以是完整对象类型。简而言之,模型可以是原生的Javascript对象。

视图

所谓视图,就是指用户所看见的。 视图的生命周期由作为一个模板开始,它将和模型合并,并最终渲染到浏览器的DOM中。与其他模板系统不同的是,AngularJS使用一种独特的形式来渲染视图。

其他模板 - 大部分模板系统工作原理,都是一开始获取一个带有特殊标记的HTML形式字符串。通常情况下模板的特殊标记破坏了HTML的语法,以至于模板是不能用HTML编辑器编辑的。然后这个字符串会被送到模板引擎那里解析,并和数据合并。合并的结果是一个可以被浏览器解析的HTML字符串。这个字符串会被.innerHTML方法写到DOM中。使用innerHTML会造成浏览器的重新渲染。当模型改变时,这整个流程又要重复一遍。模板的生存周期就是DOM的更新周期。这里我想强调是,这些模板的基础是字符串。
AngularJS - AngularJS和其它模板系统不同。它使用的是DOM而不是字符串。模板仍然是用HTML字符串写的,并且它仍然是HTML。浏览器将它解析成DOM, 然后这个DOM会作为输入传递给模板引擎,也就是我们的编译器。编译器查看其中的指令,找到的指令后,会开始监视指令内容中相应的模型。 这样做,就使得视图能“连续地”更新,不需要模板和数据的重新合并。你的模型也就成了你视图变化的唯一原因。

指令

一个指令 就是一种“由某个属性、元素名称、css类名出现而导致的行为,或者说是DOM的变化”。指令能让你以一种声明式的方法来扩展HTML表示能力。

Filters过滤器

过滤器扮演着数据翻译的角色。一般他们主要用在数据需要格式化为本地格式的时候。它参照了UNIX过滤的规则,并且也实现了“|”(管道)语法。

模块和注入器

每个AngularJS应用都有一个唯一的注入器。注入器提供一个通过名字查找对象实例的方法。它将所有对象缓存在内部,所以如果重复调用同一名称的对象,每次调用都会得到同一个实例。如果调用的对象不存在,那么注入器就会让实例的工厂(instance factory)函数创建一个新的实例。

一个模块就是一种配置注入器的实例的工厂函数的方式,我们也称它为“提供者(provider)”。

var myModule = angular.module('myModule', [])

myModule.factory('serviceA', function() {      //定义serviceA的工厂函数,myModule模块就是提供serviceA实例的工厂函数的提供者
  return {

  ......
  };
});

// create an injector and configure it from 'myModule'
var $injector = angular.injector('myModule');

// retrieve an object from the injector by name
var serviceA = $injector.get('serviceA');      //从注入器查找serviceA对象,这时注入器会让实例serviceA的工厂函数factory创建一个新的实例serviceA返回

// always true because of instance cache
$injector.get('serviceA') === $injector.get('serviceA');

注入器真正强大之处在于让方法和类型能够通过注入器,请求到他们依赖的组件,而不需要自己加载依赖。

我们看看下面动态时间的这个例子:

<!doctype html>
<html ng-app="timeExampleModule">
<head>
<script src="http://code.angularjs.org/angular-1.1.0.min.js"></script>
<script">
  angular.module('timeExampleModule', []).
      factory('time', function($timeout) {
       var time = {};
      (function tick() {
      time.now = new Date().toString();
      $timeout(tick, 1000);
      })();
      return time;
     });
    function ClockCtrl($scope, time) {
     $scope.time = time;
    }
</script>
</head>
<body>
<div ng-controller="ClockCtrl">
Current time is: {{ time.now }}
</div>
</body>
</html>

你只要把需要的依赖写在函数参数里。当AngularJS调用这个函数时,它会自动填充好需要的参数。这个例子中,当ng-controller实例化构造器ClockCtrl的时候,它自动提供了指明的依赖time实例对象。

AngularJS 命名空间

为了防止意外的命名冲突, AngularJS为可能冲突的对象名加以前缀"$"。所以请不要在你自己的代码里用"$"做前缀,以免和AngularJS代码发生冲突。

加油!

AngularJS开发指南3:Angular主要组成部分以及如何协同工作的更多相关文章

  1. AngularJS开发指南16:AngularJS构建大型Web应用详解

    AngularJS是由Google创建的一种JS框架,使用它可以扩展应用程序中的HTML功能,从而在web应用程序中使用HTML声明动态内容.在该团队工作的软件工程师Brian Ford近日撰写了一篇 ...

  2. AngularJS开发指南12:AngularJS的模板,CSS,数据绑定详解

    模板 AngularJS模板是一种声明式的规则.它包含了模型和控制器的信息,最后会被渲染成用户在浏览器中看到的视图.它是静态的DOM,包含HTML,CSS和AngularJS指定的元素和属性.Angu ...

  3. AngularJS开发指南8:AngularJS模块的详解

    在讲angularjs的模块之前,我们先介绍一下angular的一些知识点: AngularJS是纯客户端技术,完全用Javascript编写的.它使用的是网页开发的常规技术(HTML,CSS,Jav ...

  4. AngularJS开发指南4:指令的详解

    指令是我们用来扩展浏览器能力的技术之一.在DOM编译期间,和HTML元素关联着的指令会被检测到,并且被执行.这使得指令可以为DOM指定行为,或者改变它. AngularJS有一套完整的.可扩展的.用来 ...

  5. AngularJS开发指南1:AngularJS简介

    什么是 AngularJS? AngularJS 是一个为动态WEB应用设计的结构框架.它能让你使用HTML作为模板语言,通过扩展HTML的语法,让你能更清楚.简洁地构建你的应用组件.它的创新点在于, ...

  6. AngularJS开发指南15:AngularJS的创建服务,将服务注入到控制器,管理服务依赖详解

    创建服务 虽然AngularJS提供了很多有用的服务,但是如果你要创建一个很棒的应用,你可能还是要写自己的服务.你可以通过在模块中注册一个服务工厂函数,或者通过Module#factory api或者 ...

  7. AngularJS开发指南14:AngularJS的服务详解

    服务是一种由服务器端带到客户端的特性,它由来已久.AngularJS应用中的服务是一些用依赖注入捆绑在一起的可替换的对象.服务是最常和依赖注入一起用的,它也是AngularJS中的关键特性. 接下来, ...

  8. AngularJS开发指南13:AngularJS的过滤器详解

    AngularJS过滤器是用来格式化输出数据的.除了格式化数据,过滤器还能修改DOM.这使得过滤器通常用来做些如“适时的给输出加入CSS样式”等工作. 比如,你可能有些数据在输出之前需要根据进行本地化 ...

  9. AngularJS开发指南10:AngularJS依赖注入的详解

    依赖注入是一种软件设计模式,用来处理代码的依赖关系. 一般来说有三种方法让函数获得它需要的依赖: 它的依赖是能被创建的,一般用new操作符就行. 能够通过全局变量查找依赖. 依赖能在需要时被导入. 前 ...

随机推荐

  1. history介绍及bash命令快速调用

    在日常工作中,能够快速并准确的使用命令是必不可少的,下面为大家介绍一下其中的小技巧. 一.查找命令历史——history 使用history能够快速的找到之前输入过的命令. # history 大家可 ...

  2. 一个fork的面试题

    前两天有人问了个关于Unix的fork()系统调用的面试题,这个题正好是我大约十年前找工作时某公司问我的一个题,我觉得比较有趣,写篇文章与大家分享一下.这个题是这样的: 题目:请问下面的程序一共输出多 ...

  3. linux netstat 命令简解

    Netstat 简介: Netstat是在内核中访问网络及相关信息的程序,它能提供TCP连接,TCP和UDP监听,进程内存管理的相关报告.常见参数-a (all)显示所有选项,默认不显示LISTEN相 ...

  4. 通用cube refresh方案

    通用cube refresh c# script 解决方法: 需要设置的变量如下: User::varcubename,User::varolapconnstr,User::varolapdbname ...

  5. NOIP2008 普及组T1 ISBN号码 解题报告-S.B.S.

    题目描述 每一本正式出版的图书都有一个ISBN号码与之对应,ISBN码包括9位数字.1位识别码和3位分隔符,其规定格式如“x-xxx-xxxxx-x”,其中符号“-”就是分隔符(键盘上的减号),最后一 ...

  6. UVALive 5962 Strongly Connected Chemicals --最大独立集

    题意:给n个阳离子和m个阴离子,并给出相互的吸引关系,求一个最大的点集,使其中的每个阴阳离子相互吸引. 解法:枚举每条边,使该条边存在,然后建立反图,求一个最大匹配,此时的点数减去最大匹配与ans求一 ...

  7. Apache Shiro权限框架在SpringMVC+Hibernate中的应用

    在做网站开发中,用户权限必须要考虑的,权限这个东西很重要,它规定了用户在使用中能进行哪 些操作,和不能进行哪些操作:我们完全可以使用过滤器来进行权限的操作,但是有了权限框架之后,使用起来会非常的方便, ...

  8. java 13-6 Char的包装类Character

    1.Character 类在对象中包装一个基本类型 char 的值 此外,该类提供了几种方法,以确定字符的类别(小写字母,数字,等等),并将字符从大写转换成小写,反之亦然 构造方法: Characte ...

  9. localStorage实现购物车数量单价和总价实时同步(二)

    利用localStorage实时显示购物车小计和总价页面显示: 和昨天的原理相同,本地存储同时实时循环计算总价之和,注意循环时候的先清空再计算 Success is getting what you ...

  10. 总结Gerrit常用命令

    查看分支列表,带有*的分支表示是当前所在分支[root@115~~]#git branch 查看分支详细情况 (推荐这种方式)[root@115~~]#git branch -av 创建分支(比如de ...