AngularJS开发指南9:AngularJS作用域的详解(2)

注意当作用域和元素相关联的时候,AngularJS会自动给相应元素添加ng-scope类名。这个例子中的作用域范围突出显示了。子作用域的存在是很有必要的,因为迭代器要执行{{employee.name}}表达式,它会根据不同的作用域生成不同的值。同样的,{{department}}的执行是继承自根作用域的,因为只有根作用域中定义了它。

从DOM中获取作用域

作用域是作为$scope的数据属性关联到DOM上的,并且能在需要调试的时候被获取到。根作用关联的DOM就是ng-app指令定义的地方。一般来说ng-app都是放在<html>元素中的,但是也能放在其他元素中。

在控制台中获取关联的作用域:angular.element($0).scope()

作用域事件的传递

作用域中的事件传递是和DOM事件传递类似的。事件可以广播给子作用域或者传递给父作用域。举个例子:

 

<!doctype html> <html ng-app> <head> <script src="https://code.angularjs.org/angular-1.0.2.min.js"></script> <script src="https://www.linuxidc.com/script.js"></script> </head> <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> //当点击此按钮时,会触发MyEvent事件,这时会把此事件也传递给父作用域,也就是Root scope,这时它的count会增加1.当然同级的Middle scope的count也会加1. <button ng-click="$broadcast('MyEvent')">$broadcast('MyEvent')</button> //当点击此按钮时,会触发MyEvent事件,这时会把此事件传递给子作用域,也就是Leaf scope,这时它的count会增加1,当然同级的Middle scope的count也会加1. <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>

 

script.js:

function EventController($scope) { $scope.count = 0; $scope.$on('MyEvent', function() { //监听MyEvent事件 $scope.count++; }); }

作用域的声明周期

浏览器接收到事件后的一般工作流程是执行一个相应的Javascript回调。回调一执行完,浏览器就会重新渲染DOM并且重新回到等待事件的状态。

当浏览器调用AngularJS上下文之外的Javascript代码时,AngularJS是不知道模型的更改的。要正确处理模型的更改,就要使用$apply方法进入AngularJS的执行上下文。只有在$apply方法内执行的模型修改才会正确地被AngularJS处理。比如,一个指令监听DOM事件,比如ng-click,它必须在$apply方法中来执行表达式。

执行完表达式之后,$apply会进入$digest阶段。在$digest阶段,作用域会检查所有的$watch表达式,并将它们和之前的值比较。这意味着赋值语句,如$scope.username="angular"不会马上导致$watch被通知,取而代之的是它会等到$digest阶段才被通知。这种方式是合理的,因为它将多个模型的更新整合到一个$watch通知里,并且保证了一个$watch通知期间不会有其他同样的$watch执行。

创建——根作用域是在应用被$injector启动时创建的。在模板链接阶段,有些指令会创建新的子作用域。 

观察者注册——在模板链接阶段,指令会在作用域上注册观察者。这些���察者是用来将模型的改变传递给DOM的。

模型变化——为了正确地观测到模型变化,你需要并且只能在scope.$apply()中改变他们。(AngularJS的API会隐式地这么做,所以在控制器或者在$http,$timeout等服务中你不需要额外的调用$apply)。

变化的观测——在$apply的最后,AngularJS会在根作用域中执行一个$digest循环,它会将变化传递给所有子作用域。在$digest循环中,所有的$watch表达式或者函数都会被检测,来观察模型的变化。如果有变化被检测到了,$watch的监听回调就会被调用。

作用域的销毁——如果子作用域不再有用了。那么子作用域的创建者就会负责用scope.$destroy() API来将它销毁。这会停止$digest再调用此子作用域,并且让此作用域占用的内容能够被回收。

在模板编译阶段,编译器在DOM中匹配指令。指令通常分为两种:

观察型的指令,例如双花括号表达式{{expression}},会用$watch来注册一个监听者。无论表达式什么时候改变,这类型的指令都会被通知,并且能更新视图。

监听者型的指令,比如ng-click,会向DOM注册一个监听者。当DOM监听者触发,指令会执行相关的表达式并且使用$apply方法更新视图。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/fc73cc9a0a706e3244eddda3b511e24f.html