`
流浪的我
  • 浏览: 33911 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

angularjs Scope

 
阅读更多

一、什么是Scope

  scopehttp://code.angularjs.org/1.0.2/docs/api/ng.$rootScope.Scope)是一个指向应用modelobject。它也是expressionhttp://www.cnblogs.com/lcllao/archive/2012/09/16/2687162.html)的执行上下文。scope被放置于一个类似应用的DOM结构的层次结构中。scope可以监测(watch,$watchexpression和传播事件。

 

二、scope的特性

  • scope提供$watch APIhttp://code.angularjs.org/1.0.2/docs/api/ng.$rootScope.Scope#$watch),用于监测model的变化。
  • scope提供$apply APIhttp://code.angularjs.org/1.0.2/docs/api/ng.$rootScope.Scope#$apply),在“Angular realm”(controllerserverangular event handler)之外,从系统到视图传播任何model的变化。
  • scope可以在提供到被共享的model属性的访问的时候,被嵌入到独立的应用组件中。scope通过(原型),从parent scope中继承属性。
  • scopeexpression求值之时提供上下文环境。例如,{{username}}表达式是无意义的,除非它与一个特定的定义了”username”属性的scope一起进行求值。

 

三、Scope as Data-Modelscope作为数据模型)

  scope是在应用controllerview之间的纽带。在模版linkinghttp://www.cnblogs.com/lcllao/archive/2012/09/04/2669802.html)的阶段,directivehttp://www.cnblogs.com/lcllao/archive/2012/09/09/2677190.html)在scope中设置$watch表达式。$watchdirective能够得知属性的变化,使得directive将更新后的值渲染到DOM中。

  controllerdirective两者都与scope有引用,但它们两者之间没有(引用)(Both controllers and directives have reference to the scope, but not to each other)。这样的安排,将controllerdirectiveDOM中隔离开来。这是一个重要的地方,因为它让controllerview是隔离的,极大地提升了应用的可测试性(greatly improves the testing story of the applications)。

<!DOCTYPE HTML>
<html lang="zh-cn" ng-app>
<head>
    <meta charset="UTF-8">
    <title>data-model</title>
    <style type="text/css">
        .ng-cloak {
            display: none;
        }
    </style>
</head>
<body class="ng-cloak">
<div ng-controller="MyController">
    你的名字: <input type="text" ng-model="username"/>
    <button ng-click="sayHello()">欢迎</button>
    <hr/>
    {{greeting}}
</div>
<script src="../angular-1.0.1.js" type="text/javascript"></script>
<script type="text/javascript">
    function MyController($scope) {
        $scope.username = "My Little Dada";
        $scope.sayHello = function() {
            $scope.greeting = "Hello~" + $scope.username + "!";
        };
    }
</script>
</body>
</html>

  在上面的例子中我们可以注意到MyController”My Little Dada”对scope中的username属性进行赋值。然后,scope通知input进行赋值,将username的值预先填入input中。这展示了controller如何做才能够写入数据到scope中。

  相似地,controller可以将行为附加在scope中,正如那个当用户点击“欢迎”按钮时触发的sayHello方法一样。sayHello方法可以读取username属性,也可以创建greeting属性。这表明,当它们绑定到HTML input控件时,scope中的属性会自动更新。

  逻辑上,显示{{greeting}}涉及以下两点:

  • 与定义了{{greeting}}表达式的模版DOM节点一起检索scope。在这个例子中,这个scope与传递到MyController中的scope是相同的。(我们在稍后将会讨论scope的层次结构)
  • 通过之前检索的scope,对greeting表达式进行求值,然后将结果作为封闭DOM元素的text的值。

  我们可以认为,scope和它自己的属性可以作为数据,用于渲染视图。scope是所有和view相关的东西单一的真相来源(The scope is the single source-of-truth for all things view related)。

  从可测试性来看,controllerview的分离是值得欣喜的,因为它允许我们在没有渲染细节的干扰下(专注于)测试行为。 

it('should say hello', function() {
    var scopeMock = {};
    var cntl = new MyController(scopeMock);
   
    // Assert that username is pre-filled
    expect(scopeMock.username).toEqual('World');
    
    // Assert that we read new username and greet
    scopeMock.username = 'angular';
    scopeMock.sayHello();
    expect(scopeMock.greeting).toEqual('Hello angular!');
});

 四、Scope Hierarchiesscope层次结构)

  每一个angular应用有且只有一个root scope,但可以拥有多个child scope

  应用可以拥有多个child scope,因为一些directive会创建新的child scope(参考directive文档,查看哪些directive可创建新的scope,如ng-repeat)。当新的scope被创建后,他们将作为一个child scope,加入到parent scope中。这样,创建了一个与它们附属的DOM相似的树结构。

  当angular{{username}}求值时,它首先查看与当前元素关联的scopeusername属性。如果没有找到对应的属性,它将会一直向上搜索parent scope,直到到达root scope。在javascript中,这个行为被称为“原型继承”,child scope典型地继承自它们的parent

  这个例子说明应用中的scope(是怎样的),属性的原型继承。

<!DOCTYPE HTML>
<html lang="zh-cn" ng-app>
<head>
    <meta charset="UTF-8">
    <title>scope-hierarchies</title>
    <style type="text/css">
        .ng-cloak {
            display: none;
        }
        .ng-scope {
            border: 1px dashed red;
        }
    </style>
</head>
<body class="ng-cloak">
<div ng-controller="MyController">
    经理:{{employee.name}} [{{department}}] <br/>
    报告:
    <ul>
        <li ng-repeat="employee in employee.reports">
            {{employee.name}} [{{department}}]
        </li>
    </ul>
    <hr/>
    {{greeting}}
</div>
<script src="../angular-1.0.1.js" type="text/javascript"></script>
<script type="text/javascript">
    function MyController($scope) {
        $scope.department = "某部";
        $scope.employee = {
            name:"My Little Dada",
            reports: [
                {name:"Lcllao"},
                {name:"那个谁^o^"}
            ]
        };
    }
</script>
</body>
</html>

注意,angular自动放置ng-scope class到与scope粘附的元素中。<style>定义在上面的例子中,通过红色的虚线,高亮新的scope的范围。因为repeater{{employee.name}}表达式求值,child scope是必须的,但取决于表达式在哪一个scope进行求值,不同的scope有不同的结果。相似地,{{department}}的值是从root scope中原型继承得来的,只有在那个地方有,才有department属性的定义。

 

五、Retrieving Scopes from the DOM(从DOM中检索scope

  scope作为$scope数据属性附加到DOM中,可以被用于以调试作为目的的检索。(在应用中通过这个方式检索Scope是不可能的。)附加到的DOMroot scope的位置是通过ng-app directive的位置定义的。通常ng-app是放置在<html>元素中,但它也可以放置在其他元素中,例如,只有一部分视图需要被angular控制。

  在debugger中查看scope

1. 在浏览器中,对着感兴趣的元素点击右键,选择“查看元素”。我们可以看到浏览器debugger高亮了我们选中的元素。

2. debugger允许我们在console中通过$0变量去访问当前选择的元素。

3. 想查看关联的scope,我们可以在console中输入:angular.element($0).scope()

 

六、Scope Events PropagationScope事件传播)

  scope可以以类似于DOM事件的方式进行事件传播。事件可以被broadcasthttp://code.angularjs.org/1.0.2/docs/api/ng.$rootScope.Scope#$broadcast)到child scope或者emithttp://code.angularjs.org/1.0.2/docs/api/ng.$rootScope.Scope#$emit)到parent scope中。(当前scope如果有监听,也会执行) 

<!DOCTYPE HTML>
<html lang="zh-cn" ng-app>
<head>
    <meta charset="UTF-8">
    <title>scope-event-propagation</title>
    <style type="text/css">
        .ng-cloak {
            display: none;
        }
    </style>
</head>
<body class="ng-cloak">
<div ng-controller="MyController">
    root scope count:{{count}}
    <ul>
        <li ng-repeat="i in [1]" ng-controller="MyController">
            <button ng-click="$emit('MyEvent')">$emit("MyEvent")</button>
            <button ng-click="$broadcast('MyEvent')">$broadcast("MyEvent")</button>
            <br/>
            middle scope count:{{count}}
            <ul>
                <li ng-repeat="item in [1,2]" ng-controller="MyController">
                    Leaf scope count:{{count}}
                </li>
            </ul>
        </li>
    </ul>
</div>
<script src="../angular-1.0.1.js" type="text/javascript"></script>
<script type="text/javascript">
    function MyController($scope) {
        $scope.count = 0;
        $scope.$on("MyEvent", function() {
            $scope.count++;
        });
    }
</script>
</body>
</html>

七、Scope Life Cyclescope生命周期)

  浏览器正常的事件流中,当浏览器接收到事件后,它会执行一个相应的javascript回调。一旦回调函数执行完毕后,浏览器将会重绘DOM,并返回到继续等待事件的状态。

  当浏览器在angular执行环境外调用javascript代码时,这意味着angular是不知道model的改变的。要正确处理model的修改,这个命令必须通过使$apply方法进入angular执行环境。只有在$apply方法中的model变更,才会正确地被angular统计。例如,一个directive监听了DOM事件,例如ng-click,它必须在$apply方法中对表达式进行求值。

  在对表达式求值之后,$apply方法执行一个$digest。在$digest阶段里,scope检查所有$watch监听的表达式,将现在的值与旧的值作比较。脏检查(dirty checking)是异步的。这意味着赋值语句(例如$scope.username=”angular”)将不会马上导致一个$watch被通知,反而,$watch的通知将会延迟到$digest阶段。这个延迟是必须的,因为它把多个model更新联合到一个$watch通知中,这保证了在$watch通知的过程中,没有其他$watch在执行。如果一个$watch改变了model的值,那么它将会强制增加一个$digest周期。

  1) Creation(创建scope

    root scope是在应用启动的过程中,被$injectorhttp://code.angularjs.org/1.0.2/docs/api/AUTO.$injector)创建的。在模版linking的过程中,一些directive会创建新的child scope

  2) Watcher registration(注册watcher

    在模版linking过程中,directivescope中注册$watch。这些watch将会被用作向DOM传播model的值。

  3) Model mutationModel变化)

    为了让变化被正确地检测,我们需要将他们包裹在scope.$apply中。(angular API 已经隐式地做了这部操作,所以,当在controller中做同步的工作或者与$http或者$timeout一起做异步工作的时候,不需要额外的$apply调用)。

  4) Mutation observation(变化监测)

    在$apply的结尾,angular会在root scope执行一个$digest周期,这将会传播到所有child scope中。在$digest周期中,所有注册了$watch的表达式或者function都会被检查,判断model是否发生了改变,如果改变发生了,那么对应的$watch监听器将会被调用。

  5) Scope destructionscope销毁)

    当child scope不再是必须的时候,child scope的产生者有责任通过scope.$destroy() API销毁它们(child scope)。这将会停止$digest的调用传播传播到child scope中,让被child scope model使用的内存可以被gcgarbage collector)回收。

1. Scopes and Directives

  在编译阶段中,compiler依靠DOM模版匹配directivedirective通常可以分为两大类:

  • 观察型directiveObserving directives),例如dobule-curly表达式{{expression}},使用$watch方法注册监听器。无论什么时候,表达式(的值)发生改变,这类directive必须被通知,从而更新view
  • 监听型directiveListener directive),例如ng-click,注册一个监听器到DOM中。当DOM的监听器触发时,directive会执行相关的表达式,并通过使用$apply方法更新视图。

  当一个外部的事件(例如用户动作、timer或者XHR)被监听到,相关的expression必须通过$apply方法应用到scope中,让所有监听器能够正确地更新。

2. Directives that Create Scopes

  在大多数的情况中,directivescope是相互影响的,但不会创建新的scope实例。然而,一些directive(例如ng-controllerng-repeat)会创建新scope,附加child scope到对应的DOM元素中。我们通过使用angular.element(aDomElement).scope()查看任意DOM元素的scope

3. Controllers and Scopes

  在以下的情况中,scopecontroller是相互影响的:

  • controller使用scope暴露controller方法到模版中(查看ng-controllerhttp://code.angularjs.org/1.0.2/docs/api/ng.directive:ngController))。
  • controller定义方法(行为),可以改变modelscope上的属性)。
  • controller可能在model中注册watch。这些watch会在controller行为执行之后马上执行。

4. Scope $watch Performance ConsiderationsScope $watch的性能考虑)

  在angular中,为了检测属性的变化而对scope进行脏检测(Dirty checking),是一个普遍的操作。为此,这要求dirty checking函数必须是高效的。应小心dirty checking函数不要做任何DOM访问操作,因为DOM访问的速度比访问javascript对象属性的速度要慢好几个数量级。 

 

 

分享到:
评论

相关推荐

    AngularJS Scope(作用域)

    在AngularJS中,当你创建一个控制器时,通常会将 `$scope` 对象作为参数传递。例如: ```javascript var app = angular.module('myApp', []); app.controller('myCtrl', function($scope) { $scope.carname = ...

    AngularJS 多指令Scope问题的解决

    在AngularJS中,Scope是应用程序中数据绑定的核心组件,它作为控制器、指令以及视图之间的数据桥梁。然而,当涉及到多指令共享同一个Scope时,可能会出现一些复杂的问题。本文将深入探讨AngularJS中多指令Scope问题...

    AngularJS Novice to Ninja (英文)

    3. 第三章“AngularJS Scope & Events”,深入探讨了作用域(Scope)的概念以及事件处理,作用域是连接模型和视图的桥梁,事件则是AngularJS中实现交互的重要机制。 4. 第四章“Multiple Views and Routing”讲述了...

    AngularJS入门教程之Scope(作用域)

    AngularJS Scope(作用域) Scope(作用域) 是应用在 HTML (视图) 和 JavaScript (控制器)之间的纽带。 Scope 是一个对象,有可用的方法和属性。 Scope 可应用在视图和控制器上。 如何使用 Scope 当你在 AngularJS...

    AngularJS全局scope与Isolate scope通信用法示例

    在AngularJS中,作用域(scope)是应用中的核心概念之一,它是一个JavaScript对象,用来保存模型(Model)的属性。作用域为视图和控制器之间提供了连接,也可以用于组件和指令之间的数据通信。 AngularJS中有两种...

    angularjs 源码解析之scope

    $scope 的使用贯穿整个 Angular App 应用,它与数据模型相关联,同时也是表达式执行的上下文.有了 $scope 就在视图和控制器之间建立了一个通道,基于作用域视图在修改数据时会立刻更新 $scope,同样的 $scope 发生改变时...

    AngularJS-Scope.SafeApply:AngularJS $ scope。$ apply()没有麻烦和错误

    AngularJS-Scope.SafeApply AngularJS $ scope。$ apply()没有麻烦和错误:) 关于 AngularJS的核心功能是范围,变量和绑定的使用。 在代码级别更新值并回显DOM或应用程序的过程围绕着对范围运行摘要来查看发生了...

    AngularJS - Novice to Ninja.pdf.pdf )

    Chapter 3 AngularJS Scope & Events . . . . . . . . . . . . 45 Scope Demystified . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 Writing Access with ...

    AngularJS中的$watch(),$digest()和$apply()区分

    AngularJS $scope里面的$watch(),$digest()和$apply()是AngularJS的核心函数,学习AngularJS必须理解这几个函数。 在绑定$scope中的变量到view的时候,AngularJS自动在内部创建一个”Watch”。”Watch”用于监听...

    jquery操作angularjs对象

    在示例中,通过jQuery改变DOM元素内容,但这个改变并不会自动反映到AngularJS的scope上,从而导致视图和模型不同步。要解决这个问题,需要在修改模型后手动调用`scope.$apply()`函数,以确保AngularJS能够检测到模型...

    浅谈AngularJs指令之scope属性详解

    本文将深入探讨AngularJs指令中的scope属性,这是一个非常重要的特性,因为它决定了指令如何与数据模型进行交互。 首先,AngularJs中的指令是通过调用模块的.directive()方法创建的。该方法的主体框架接受两个参数...

    深入理解AngularJs-scope的脏检查(一)

    在AngularJS中,子scope可以继承父scope的属性,而隔离作用域用于组件或指令中创建独立的数据环境,防止与其他scope产生冲突。 此外,scope还支持事件机制,包括`$on`、`$broadcast`和`$emit`: - `$on`:注册事件...

    深入理解Angular.JS中的Scope继承

    AngularJS中scope之间的继承关系使用JavaScript的原型继承方式实现。本文结合AngularJS Scope的实现以及相关资料谈谈原型继承机制。下面来看看详细的介绍: 基本原理 在JavaScript中,每创建一个构造函数...

    AngularJS书两本

    接着,《AngularJS_深度剖析与最佳实践》可能会更深入地探讨AngularJS的高级话题,如模块化、路由、指令的高级用法、以及$scope的工作原理。模块化有助于组织大型应用,而路由则允许在单页应用(SPA)中实现页面导航...

    通过angularjs的ng-repeat指令看scope的继承关系

    这个过程涉及到AngularJS的核心概念之一——Scope,它是应用程序中的数据模型,也是连接视图和控制器的桥梁。本文将深入探讨`ng-repeat`与Scope的继承关系。 首先,理解Scope的基本概念是关键。在AngularJS中,每个...

    AngularJS中scope的绑定策略实例分析

    在AngularJS中,数据绑定是其核心特性之一,而作用域(scope)是实现数据绑定的关键。作用域在AngularJS中是数据模型和视图之间的一个桥梁,数据变化能够实时反映到视图中,同时视图的更改也能够实时反映到数据模型...

    Angularjs 合集 Angularjs 合集

    这可能包括深入讲解Scope、Controller、Directives和Filters的内部工作机制,以及如何利用AngularJS的模块系统构建大型应用。可能还会讨论AngularJS与其它技术如RESTful API、Bootstrap或jQuery的集成,以及如何使用...

Global site tag (gtag.js) - Google Analytics