angular学习(五)—— Scopes
转载请写明来源地址:http://www.52php.cn/article/p-ckoromyb-bph.html Scopes简介Scopes是一个指向application模型的对象,是表达式执行的上下文,模拟application的DOM结构构成自己的层次结构。Scope可以观察表达式和传播事件。 Scopes特点Scopes提供了API $watch观察model的变化。 Scope作为Data-ModelScope是Controller和view之间的粘合剂,在程序链接阶段directives在scopes中设置$watch表达式,$watch允许directives得到属性改变的通知,并允许directives将改变后的值呈现给DOM视图。 <!DOCTYPE html> <html> <head> </head> <script src="script/angular.min.js"></script> <script> angular.module('scopeExample',[]) .controller('MyController',['$scope',function($scope) { $scope.username = 'World'; $scope.sayHello = function() { $scope.greeting = 'Hello ' + $scope.username + '!'; }; }]); </script> <body> <div ng-app="scopeExample" ng-controller="MyController"> Your name: <input type="text" ng-model="username"> <button ng-click='sayHello()'>greet</button> <hr> {{greeting}} </div> </body> </html> 在上面的例子中,MyController首先将World赋值给scope中的username属性,scope将通知input这次赋值,然后将username的值预先填入到输入框中,这里演示了controller怎么样将数据写入到scope中。 同样controller可以分配行为给scope,比如这个例子中的sayHello方法,当用户点击greet按钮时,sayHello方法就会被调用。sayHello方法会去读取username属性并创建一个greeting属性。这里演示的是绑定到input部件的属性的自动更新。 greeting属性的呈现逻辑上分为两步: 1.在DOM中的模板里定义了{{greeting}},首先检索DOM关联的scope。 2.针对以上检索到的scope,计算求值greeting,并将结果分配给这个enclosing DOM元素的文本。 你可以把scopes及其属性是用于呈现view的数据,而且是view相关的单一真实数据来源。
Scope层次结构每个angular的application都有一个root scope,但是可以有多个child scopes。 application可以有多个scopes,因为一些directives可以创建新的child scopes,新的scopes一旦被创建,就会被作为child scope增加到它的parent scope中,和他们链接的DOM一样,构成一个树形结构。 当Angular对{{name}}属性求值时,先在相关联的scope内寻找这个属性,如果没找到它就会去parent scope中找,一直搜到root scope。在JavaScript中这种行为被称为prototypical inheritance,child scopes prototypically继承于他们的parent scope。 这个例子讲解了application中点scopes,还有属性的prototypical inheritance,例子后面的一张图描诉了scope的边界。<!DOCTYPE html> <html> <head> </head> <script src="script/angular.min.js"></script> <script> angular.module('scopeExample',[]) .controller('GreetController','$rootScope',function($scope,$rootScope) { $scope.name = 'World'; $rootScope.department = 'Angular'; }]) .controller('ListController',function($scope) { $scope.names = ['Igor','Misko','Vojta']; }]); </script> <style> .show-scope-demo.ng-scope,.show-scope-demo .ng-scope { border: 1px solid red; margin: 3px; } </style> <body ng-app="scopeExample"> <div class="show-scope-demo"> <div ng-controller="GreetController"> Hello {{name}}! </div> <div ng-controller="ListController"> <ol> <li ng-repeat="name in names">{{name}} from {{department}}</li> </ol> </div> </div> </body> </html>   注意到Angular自动将scope影响到的元素附上了ng-scope的class样式。style定义了在新的scope创建的地方都会红色高亮显示。{{name}}在不同的scope内会得出不同的值,{{department}} prototypically继承于root scope。
在DOM中检索ScopesScope作为一种数据属性附加到DOM中,可以用来调试目的的检索。root scope被附加到ng-app声明的DOM节点。通常ng-app放在元素,但它可以放在其他元素,例如,只有部分视图需要由Angular控制。 在调试器中检查scope: 1.在浏览器中右键你感兴趣的元素,并且选择检查元素(推荐chrome浏览器),您应该看到浏览器调试器与你点击高亮显示的元素。 2.调试器允许您访问当前选中的元素在Console输入 $0 3.在Console中执行angular.element( $0).scope()来检索scopeScope事件传播Scopes也能传播事件,就像传播DOM事件一样,可以通过broadcast广播到子children scopes,通过emit扩散到parent scope<!DOCTYPE html> <html ng-app="eventExample"> <head> <meta charset="uft-8"/> <title></title> </head> <script src="script/angular.min.js"></script> <script> angular.module('eventExample',[]) .controller('EventController',function($scope) { $scope.count = 0; $scope.$on('MyEvent',function() { $scope.count++; }); }]); </script> <body> <div ng-controller="EventController"> Root scope <tt>MyEvent</tt> count: {{count}} <ul> <li ng-repeat="i in [1]" ng-controller="EventController"> <button ng-click="$emit('MyEvent')">$emit('MyEvent')</button> <button ng-click="$broadcast('MyEvent')">$broadcast('MyEvent')</button> <br> Middle scope <tt>MyEvent</tt> count: {{count}} <ul> <li ng-repeat="item in [1,2]" ng-controller="EventController"> Leaf scope <tt>MyEvent</tt> count: {{count}} </li> </ul> </li> </ul> </div> </body> </html> 
Scope生命周期浏览器接受事件的普通流程是这样的,它会执行相应的javascript回调,一旦执行完毕浏览器将会重新呈现DOM并返回多个等待事件。 当浏览器调用进入javascript的代码时,因为这些代码在Angular的执行上下文之外,意味着Angular根本无从得知model的更改。模型修改正确的执行流程是通过 $apply方法进入到Angular的执行上下文。在 $apply方法中仅仅模型改变将被Angular执行。例如一个监听DOM事件的directive,比如ng-click,它必须在 $apply方法中计算表达式的值。 在计算玩表达式的值之后, $apply会调用 $digest方法。在 $digest阶段,scope会检查所有的 $watch表达式,并且比较它们和之前的值是否相同。这种脏检查是异步的,这意味着比如 $scope.username=”angular”这项任务不会立即引起 $watch的更改,取而代之的是 $watch通知被延迟到 $digest阶段。这种延迟是可取的,因为它把多个模型的改变聚集成一个 $watch通知,并且能保证同时 $watch通知期间没有其它 $watches在运行。如果 $watches改变了模型的值,它将被强制附加到 $digest周期。 $apply()伪代码function $apply(expr) {
try {
return $eval(expr);
} catch (e) {
$exceptionHandler(e);
} finally {
$root.$digest();
}
} Scope周期概要: 1.创建 在Angular程序的引导阶段,root scope通过
$injector被创建。在template链接阶段,一些directives创建新的child scopes。 2.Watcher注册 在template链接阶段,directives注册Watcher到scope。这些watches被用于将模型的值传播到DOM中。 3.Model变化 为了让变化正确的被观察到,你应该仅仅使用scope.
$apply()。Angular APIs会隐含的做这些,所以不需要额外的调用
$apply()在controllers中,或者一些异步工作中比如
$http,$timeout or
$interval 服务。 4.观察变化 在
$apply的末尾,Angular会在root scope内调用
$digest,会在所有的child scopes传播,在
$digest周期,所有的
$watched的表达式或者函数将被检查模型的改变,如果改变发生,
Scopes和Directives在编译阶段,编译器将directives和DOM template进行匹配。directives通常分为两类: 1.观察directives,比如双大括号的表达式{{expression}},用 $watch()方法注册监听器。当表达式发生改变时,这种directives需要被通知,以便可以更新视图。 2.监听directives,比如ng-click,注册一个监听器在DOM上,当DOM的监听器被激活,这个指令将执行相应的表达式,并且用$apply()方法更新视图。 当一个外部事件 (如用户操作,定时器或XHR)收到时,相关的表达式必须通过$apply()应用到scope中,以便所有的listeners被正确的更新。创建Scopes的Directives在大多数情况下,directives和scopes相互作用,但是不会创建一个新的scope实例。然而一些命令,比如ng-controller和ng-repeat,会创建新的child scopes并且附加child scopes到相应的DOM元素中。你可以用angular.element(aDomElement).scope()方法检索任意DOM元素对应的scope。 Controllers和ScopesScopes和controllers直接的相互作用有以下几种情况: Scope $watch的性能考虑在Angular中,脏检查scope是否有属性改变是一项非常常规的操作。因此脏检查函数必须是高效的,应该非常小心的注意到,脏检查函数不能做任何DOM访问,DOM访问比JavaScript对象属性访问慢了好几个数量级。 Scope $watch的深度脏检查可以使用三种策略:通过引用,通过集合内容,通过值。这三种脏检查可以检测到不同的变化,并且有不同的性能特征。 2.通过集合内容(scope.$watchCollection (watchExpression,listener)) 3.通过值(Watching by value (scope.$watch (watchExpression,listener,true)) 与浏览器的event loop集成这张图和下面的例子讲解Angular和浏览器之间的事件循环。 Angular通过提供它自己的事件进程循环修改了普通的javascript流程。它吧javascript切割成两部分:传统部分和Angular执行上下文部分。在Angular执行上下文中仅仅一些操作可以受益:Angular数据绑定,异常处理,属性检测等等。你还可以调用$apply()从javascript执行上下文进入到Angular执行上下文。请记住一点,在大多数地方(controllers,services)已经被隐式的调用了。仅仅实现当自定义事件或者调用第三方库的回调函数时,$apply()才需要被显式的调用。 下面讲解一下hello world的示例,这个示例所做的是当用户输入字符到文本框中,如何实现了数据绑定。 <!DOCTYPE html> <html lang="en" ng-app> <head> <script src="script/angular.min.js"></script> </head> <body> Your name: <input type="text" ng-model="name" placeholder="World"> <hr> Hello {{name || 'World'}}! </body> </html>
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- Firebase作为AngularJS的后端
- angularjs – 量角器在中继器内找到元素
- angular – 实验装饰器警告VSCODE
- scala – 关于Future.firstCompletedOf和Garbage Collect机
- 如何评估来自bash/shell脚本的http响应代码?
- 由Lighthouse测量的Hello World Angular CLI(为什么慢而且巨
- 在bash中捕获来自“docker stop”的信号
- 基于.NET的推送通知服务
- angularjs – 如何在Angular UI路由器中预加载模板?
- -bash: /usr/local/bin/pod: /System/Library/Frameworks/R