AngularJS作用域:提供了在一个模型中表示的数据,把AngularJS应用程序的其他组件,模块,服务和模板都绑定在一起
1.了解作用域
一个应用程序的数据模型(结合视图,业务逻辑,服务器端数据)
1.1.根作用域和应用程序之间的关系
应用程序启动,根作用域创建。($rootScope将数据储存在应用层)
在run()块初始化(也可在模块组件中访问)。
angular.module('myApp',[]).run(function($rootScope){ $rootScope.rootValue=5; }) .controller('myController',function($scope,$rootScope){ $scope.value=10; $scope.difference=function(){ return $rootScope.rootValue-$scope.value; } })
1.2.作用域和控制器之间的关系
控制器:扩大作用域来提供业务逻辑。(Model对象上的controller()方法创建:把控制器注册为模块中的提供器,实例的创建发生在ng-controller指令被链接到AngularJS模板)
angular.module('myApp',[]). value('start',200).controller('Counter',['$scope','start',function($scope,startingValue){ //新子作用域创建,$scope访问,start提供器被注入到控制器,作为startingValue被传递到控制器函数 }])
控制器负责连接到该作用域内的任何业务逻辑。意味着处理对作用域的更新更改,操作作用域值,发出基于该作用域的状态的事件
实现依赖注入的控制器,初始化值,inc(),dec(),calcDiff() 实现基本逻辑
var myModule = angular.module('myApp', []); myModule.value('start', 200); myModule.controller('Couter', ['$scope', start, function($scope, start) { $scope.start = start; $scope.current = start; $scope.difference = 0; $scope.change = 1; $scope.inc = function() { $scope.current += $scope.change; $scope.calcDiff(); }; $scope.dec = function() { $scope.current -= $scope.change; $scope.calcDiff(); } $scope.calcDiff = function() { $scope.difference = $scope.current - $scope.start; }; }])
1.3.作用域和模板之间的关系
模板为AngularJS应用程序提供视图。(HTML元素使用ng-controller属性被定义为控制器)(控制器的HTML元素及子元素内部,控制器可用于表达式和其他AngularJS功能)
在一个作用域中的值可以用 ng-model 指令链接到模板的 <input> <select> <textarea> 元素的值中(当用户改变输入元素的值时,作用域被自动更新)
<input type="number" ng-model="valueA">
{{expression}}:把作用的属性 函数 添加到表达式
<span ng-click="addValues(valueA,valueB)">Add Values{{valueA}}&{{valueB}}</span>
ng-click指令把浏览器单击事件绑定到作用域中:addValues()函数 addValues()函数中,不是必须的 ng-click和其他的AngularJS指令会自动对表达式求值。
<!DOCTYPE html> <html lang="en" ng-app="myApp"> <head> <meta charset="UTF-8"> <title>scope_template</title> <link rel="stylesheet" href="bootstrap.css"> </head> <body> <div class="panel panel-primary"> <div class="panel-heading">cal with sums(AngularJS)</div> <div class="panel-body"> <div class="row"> <div class="col-md-12"> <form class="form-horizontal" role="form" ng-controller="SimpleTemplate"> <div class="form-group"> <label class="col-md-2 control-label">ValueA:</label> <div class="col-md-10"> <input class="form-control" type="number" ng-model="valueA"> </div> </div> <div class="form-group"> <label class="col-md-2 control-label">ValueB:</label> <div class="col-md-10"> <input class="form-control" type="number" ng-model="valueB"> </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <button class="btn btn-primary" ng-click="addValues(valueA,valueB)">click to add value</button> <button class="btn btn-primary" ng-click="clearValues(valueA,valueB)">click to clear value</button> </div> </div> <div class="form-group"> <label class="col-md-2 control-label">ValueB:</label> <label class="col-md-10 control-label" style="text-align: left">{{valueC}}</label> </div> </form> </div> </div> </div> </div> <script src="angular-1.3.0.js"></script> <script type="text/javascript"> angular.module('myApp',[]).controller('SimpleTemplate', function($scope){ $scope.valueA=10; $scope.valueB=20; $scope.valueC=30; $scope.addValues=function(v1,v2){ var v=angular.$rootScope; $scope.valueC=v1+v2; } $scope.clearValues=function(v1,v2){ $scope.valueA=0; $scope.valueB=0; // v1=0; // v2=0; } }) </script> </body> </html>
(基本Angular模板,实现控制器 把多个字段链接到作用域 提供值并显示结果(CSS用bootstrap))
1.4.作用域和后端服务器数据之间的关系
用于AngularJS的数据 往往是后端数据源(如数据库)。
- 经 由 AngularJS服务 来访来自数据库或其他后端资源的数据(包括读取 更新数据)
- 确保从 数据库读出的数据 对 作用域 更新(又更新了视图),避免直接从数据库中操作HTML值 (可能会导致作用域与视图不同步)
- 把对 数据库或其他后端源 所做的更改 反映到作用域。可以先更新作用域,然后用一个服务对数据库进行更新 执行此操作。也可以先更新数据库,然后用来自数据库的结果在作用域内重新填充适当的值。
1.5.作用域的生命周期
作用域的数据经过:
1.创建
2.监听器注册
3.模型变化
4.变化观察
5.作用域销毁
创建阶段:一个作用域初始化时,创建阶段产生。启动应用程序会创建根作用域(ng-controller or ng-repeat)创建子作用域模板
$scope.$digest() digest循环与浏览器事件循环互动。把对模型的更改更新到DOM元素,执行任何已注册的监听函数。
监听注册器阶段:为作用域中的值注册监视函数。监视器自动将模型的更改传播到DOM元素
$.scope.watchedItem='myItem'; $scope.counter=0; $scope.$watch('name',function(newValue,oldValue){ $scope.watchedItem=$scope.counter+1; })
模型变化阶段:发生在作用域内的数据变化时。AngularJS代码进行更改时,名为$apply()的作用域函数更新模型,调用$digest()函数更新DOM和监听器(或由$http,$timeout和$interval服务所做的更改自动在DOM中更新)
变化观察阶段:$digest()方法被digest循环,$apply()调用或手动执行,变化观察发生。会对所有用于更改的监听器求值。发生变化,$digest调用$watch监听器更新DOM
作用域销毁阶段:$destroy()从浏览器内存中删除作用域。停止$digest()调用并删除监听器。
2.实现作用域层次结构
作用域特点:被组织成层次结构。
保持作用域条理,将它们与所代表的视图上下文联系起来($digest()方法用作用域层次来为适当的监听器和DOM元素传播作用域的变更)
兄弟关系作用域:
<div ng-controller="controllerA"></div> <div ng-controller="controllerB"></div>
父子作用域:(controllerA是controllerB的父)
<div ng-controller="controllerA"> <div ng-controller="controllerB"></div> </div>
可以从一个控制器访问父作用域的值,但不能访问它的兄弟或子作用域的值。(父元素作用域改变,子控制器中的DOM值改变)
实现基本作用域:访问层次结构每个级别的属性
<!DOCTYPE html> <html lang="en" ng-app="myApp"> <head> <meta charset="UTF-8"> <title>AngularJS Scope Hierarchy</title> </head> <body> <div ng-controller="LevelA"> <h3>{{title}}</h3> ValueA={{valueA}} <input type="button" ng-click="inc()" value="+" /> <div ng-controller="LevelB"> <hr> <h3>{{title}}</h3> ValueA={{valueA}}<br/> ValueB={{valueB}} <input type="button" ng-click="inc()" value="+"> <div ng-controller="LevelC"> <h3>{{title}}</h3> ValueA={{valueA}}<br/> ValueB={{valueB}}<br/> ValueC={{valueC}} <input type="button" ng-click="inc()" value="+"> </div> </div> </div> <script type="text/javascript" src="angular-1.3.0.js"></script> <script type="text/javascript" src="scope_hierarchy.js"></script> </body> </html>
实现控制器的层次结构并呈现作用域的多个层次的结果
angular.module('myApp', []). controller('LevelA',function($scope){ $scope.title="Level A"; $scope.valueA=1; $scope.inc=function(){ $scope.valueA++; } }). controller('LevelB',function($scope){ $scope.title="Level B"; $scope.valueB=1; $scope.inc=function(){ $scope.valueB++; } }). controller('LevelC',function($scope){ $scope.title="Level B"; $scope.valueC=1; $scope.inc=function(){ $scope.valueC++; } });
3.发出和广播活动
作用域特点:具有在作用域层次结构内发出和广播事件的能力。
$emit():沿着父作用域层次向上发送一个事件。任何已注册该事件的祖先作用域都会收到通知
$broadcast():把一个事件广播给下方的子作用域层次。任何已注册该事件的后代作用域都会收到通知
$on():处理发出或者广播的事件。scope.$on(name,listener)
在层次结构中实现$emit() $broadcast()事件
var myModule=angular.module('myApp', []); myModule.controller('Characters', function($scope){ $scope.names=['Frodo','Aragorn','Legolas','Gimli']; $scope.currentName=$scope.names[0]; $scope.changeName=function(){ $scope.currentName=this.name; $scope.$broadcast('CharacterChanged', this.name); }; $scope.$on('CharacterDeleted', function(event,removeName){ var i=$scope.names.indexOf(removeName); $scope.names.splice(i,1); $scope.currentName=$scope.names[0]; $scope.$broadcast('CharacterChanged', $scope.currentName); }); }) myModule.controller('Character', function($scope){ $scope.info={ 'Frodo':{weapon:'Sting',race:'Hobbit'}, 'Aragorn':{weapon:'Sword',race:'Man'}, 'Legolas':{weapon:'Bow',race:'Elf'}, 'Gimli':{weapon:'Axe',race:'Dwarf'} }; $scope.currentInfo=$scope.info['Frodo']; $scope.$on('CharacterChanged', function(event,newCharacter){ $scope.currentInfo=$scope.info[newCharacter]; }); $scope.deleteChar=function(){ console.log("delete char") delete $scope.info[$scope.currentName]; $scope.$emit('CharacterDeleted',$scope.currentName); }; })
控制器的作用域层次结构
<!DOCTYPE html> <html lang="en" ng-app="myApp"> <head> <meta charset="UTF-8"> <title>scope events</title> <style type="text/css"> div {padding: 5px;font: 18px bold;} span {padding: 3px;margin: 12px;border: 5px ridge;cursor: pointer;} label {padding: 2px;margin: 5px;font: 15px bold;} p {padding-left: 22px;margin: 5px;} </style> <link rel="stylesheet" type="text/css" href="bootstrap.css"> </head> <body> <div ng-controller="Characters" class="panel panel-primary"> <div class="panel-body"> <button ng-repeat="name in names" ng-click="changeName()" class="btn btn-primary">{{name}}</button> <div ng-controller="Character"> <hr> <label>Name:</label> <p>{{currentName}}</p> <label>Race:</label> <p>{{currentInfo.race}}</p> <label>Weapon:</label> <p>{{currentInfo.weapon}}</p> <button ng-click="deleteChar()">delete</button> </div> </div> </div> </body> <script type="text/javascript" src="angular-1.3.0.js"></script> <script type="text/javascript" src="scope_events.js"></script> </html>
使用$broadcast() $emit()发送更改 通过作用域层次删除事件
作用域与模板视图,控制器,模块和服务有直接关系。作用域也可作为数据库或其他服务器端数据源的代表。
作用域的生命周期被链接到浏览器的事件循环中