NO END FOR LEARNING

Writing blog if you feel tired | 学海无涯 苦写博客

开始!AngularJS!(三)- 深入作用域

| Comments

什么是作用域?它做了些什么事情?

作用域是一个存储应用数据模型的对象
没错,它是概念也是一个对象

作用域为表达式提供了一个执行上下文
作用域为表达式提供执行环境,比如像表达式{ {name} },必须在一个拥有该属性的作用域中才能执行

作用域的层级结构对应于DOM树结构
一个应用可以有多个作用域,当新作用域被创建的时候,他们会被当成子作用域添加到父作用域下,这使得作用域会变成一个和相应DOM结构一个的树状结构。

作用域可以监听表达式的变化并传播事件
作用域提供了($watch)方法监听数据模型的变化
作用域提供了($apply)方法把不是由Angular触发的数据模型的改变引入Angular的控制范围内(如控制器,服务,及Angular事件处理器等)

作用域是Web应用的控制器和视图之间的粘结剂
控制器和指令都持有作用域的引用,于是我们可以这样理解它们之间的传递关系:
控制器 –> 作用域 –> 视图(DOM)
指令 –> 作用域 –> 视图(DOM)

何时会产生一个作用域?

于是,你肯定会想要知道,一个作用域的范围是什么?即何时会产生一个作用域?

1.创建控制器时会产生作用域(这个很明显,控制器的构造函数会传入$scope对象)
2.某些指令也会产生作用域

作用域层级

一般情况下,当新的作用域被创建时,它是以子级的形式被创建,嵌入在当前父级作用域,这样就形成了与其所关联的DOM树相对应的一个作用域的树结构。

继承

作用域中定义的属性对于所有子作用域都是可见的,只要子作用域没有定义同名属性。

换句话说,当AngularJS执行表达式{ {name} },它首先会在与当前节点相关的作用域中查找叫做name的属性。如果没找到,则继续向上层作用域搜索,直到根作用域$rootScope。在Javascript中,这被称为原型类型的继承,子作用域以原型的形式继承自父作用域。

上面引入了一个新的概念和对象根作用域$rootScope,正如上面所介绍的,作用域的结构对应于DOM结构,那么最顶层,就和DOM树有根节点一样,每个Angular应用有且仅有一个 根作用域$rootScope。

我们来看个一个具体的例子,贯穿一下上面所提到的概念:

1
2
3
4
5
6
7
8
<body ng-app="listApp">
    <div ng-controller="listController">
        my name is <input type="text" ng-model="name"/>
        <ul ng-repeat="friend in friends">
            <li>Hi { {friend} }, { {introduce()} }</li>
        </ul>
    </div>
</body>
1
2
3
4
5
6
7
8
angular.module("listApp", [])

.controller("listController", function ($scope) {
    $scope.friends = ["Lily","Kate","Mike"];
    $scope.introduce = function() {
        return "this is " + $scope.name + ".";
    };
});

在jsfiddle中查看,http://jsfiddle.net/benweizhu/wLufL8p1/1/

在这个例子中,你可能会看到和上一节定义控制器的方式不同。没错,上一节已经说过,以直接定义函数的方式定义控制器并不是常用的方式,只是为了让你知道控制器的本质是函数。

这里你不用关心定义控制器的方式,之后的章节会讲解。你需要知道的是,这里定义了一个app叫做listApp,里面定义了一个控制器listController。在这个控制器中定义了两个模型(Model)对象name,数组friends和一个函数introduce(),在模板(HTML)上使用了ng-repeat指令来迭代数组friends里面的结果,通过表达式来解析遍历结果和调用函数。

在控制器中初始化了friends,映射了这样的传递关系:控制器 –> 作用域 –> 视图(DOM)

有一点要注意的,指令ng-repeat在执行时,会在每一次遍历都创建一个名字是friend的变量,但是你从结果中看到,页面上friend的值并没有重复。那是因为,AngularJS将每个friend都放在了不同的作用域中,这就是上面提到的,某些指令会产生作用域。

于是乎,在这个app中,就不止一个作用域了,有四个作用域,其中三个作用域是同级的,它们都嵌入在父作用域listController。根据继承的关系,父作用域中的属性对子作用域是可见的,所以{ {introduce()} }表达式可以调用函数introduce。

如果你希望更深入的了解作用域的层级和产生,可以运用Chrome的插件Batarang,它可以帮助你分析AngularJS层级结构。

参考资料:

1.《精通AngularJS》
2.http://www.ngnice.com/docs/guide/scope
3.http://www.angularjs.cn/A00y

开始!AngularJS!(二)- 入门:视图,模板,模型,控制器和作用域

| Comments

在AngularJS中,视图是模型在模板中的映射的结果(模型(Model)和视图模型的绑定(View Model))。这意味当模型发生变化时,视图上的绑定内容会对应更新。

模型

看第一个的例子,模型与模板:

1
2
3
4
<body ng-app>
    <input type="text" ng-model="name"/>
    { {name} }
</body>

在jsfiddle中查看,http://jsfiddle.net/benweizhu/j6b5271r/

在这个例子中,使用了一个HTML本身没有的语法ng-model=“name”,它是AngularJS扩展的HTML语法,叫做ng-model指令,还用到了,AngularJS的数值表达式。

我们知道在大部分传统模板系统中,对模板的渲染都是线性单向的过程:模型和模板混合在一起产生标记的计算结果。当任何模型发生改变后都需要模板重新计算。

在AngularJS中,当输入框中的内容改变时,对应的模型name会发生改变,AngularJS会检测到模型发生改变,重新渲染模板中与该模型绑定的视图部分。

这是AngularJS提供的最基本也是最重要的功能之一,数据的双向绑定

控制器

再来第二个例子,模型和控制器:

1
2
3
4
5
<body ng-app>
    <div ng-controller="textController">
         <input type="text" ng-model="name"/>
    </div>
</body>
1
2
3
var textController = function($scope){
    $scope.name="benwei";
}

在jsfiddle中查看,http://jsfiddle.net/benweizhu/m5gue0zs/

在这里,用到了AngularJS中的另一个指令ng-controller,在这个Controller的范围内,定义了一个模型name,我们通过模板域模型$scope对象得到controller范围内定义的模型name,并赋值。

在例子中,我们通过$scope对象将模型数据name传递给Controller,从而进行数据的初始化。

虽然,一般情况下,我们不会用这样的方式去建立controller,但是我们可以清晰的看到,在AngularJS中,一个Controller其实就是JavaScript中的一个函数。所以,Controller可以做事情是很多,它并通过$scope对象与模型关联,从而可以实现对模型的赋值以及其他相关逻辑行为的定义。

作用域

这里你看到了另一个重要对象$scope,作用域(Scope)是AngularJS的重要概念,它可以看做一种粘合剂,让模板,模型和控制器工作在一起。AngularJS通过作用域,以及模板中包含的信息,数据模型,控制器,让模型和视图保持位置的分离,内容的同步。任何对模型的改变都会反映到视图,任何视图的改变也会映射到模型中。

大部分Web应用都是基于MVC的模式,也衍生出许多中MVC的变种(如MVVM(Model View ViewModel)),但AngularJS宣称自己是MVW(Model View Whatever)。

在本节,最重要的是了解视图,模板,模型,控制器之间的关系,以及对作用域对象$scope有一个基本的了解。我们可以在之后一起去了解一下这个Whatever到底是什么含义。

本节中遇到的概念:

模板(Template) | 带有Angular扩展标记的HTML
指令(Directive) | 用于通过自定义属性和元素扩展HTML的行为
模型(Model) | 用于显示给用户并且与用户互动的数据
作用域(Scope) | 用来存储模型(Model)的语境(context)。模型放在这个语境中才能被控制器、指令和表达式等访问到
表达式(Expression) | 模板中可以通过它来访问作用域(Scope)中的变量和函数
视图(View) | 用户看到的内容(即DOM)
数据绑定(Data Binding) | 自动同步模型(Model)中的数据和视图(View)表现
控制器(Controller) | 视图(View)背后的业务逻辑

参考资料:

1.《精通AngularJS》
2.http://www.ngnice.com/docs/guide/concepts