前言
为了对AngularJS的控制器了解更深,本次进行详细的测试。
AngularJS控制器基本使用
首先,
定义一个控制器:
controller("XXName",function(……){});然后绑定到HTML元素中去。这样,在该Controller中定义的值和方法,就可以在此HTML元素中使用。
控制器的作用域是$scope,该变量是一个普通的Json对象。 里面可以定义属性或者方法。在$scope中定义的变量和方法,只能在该controller中使用。
如果要使用全局的作用域,可以使用$rootScope,但是一般情况,尽量避免使用全局作用域。
Controller的定义方法,可以通过另外一种显式的DI注入:
Controller的定义方法,可以通过另外一种显式的DI注入:
xxx.controller("xxxName",["$scope","$rootScope",function($scope,$rootScope){……} ]);
AngularJS控制器复用
Controller可以复用。同一个Controller可以在不同的元素中定义。
但是需要注意的是,每个Controller对应的控制域是不同的。也即$scope是独立的,都是继承于$rootScope。但是各自为政,互不干扰。
AngularJS控制器继承
不过在,子Scope与父scope中,子scope可以覆盖父scope的属性。继承关系如下图:
见下面例子:
<!DOCTYPE html> <html ng-app="exampleApp"> <head> <Meta charset="utf-8"> <title>控制器</title> <script src="angular.js"></script> <link href="bootstrap.css" rel="stylesheet" /> <link href="bootstrap-theme.css" rel="stylesheet" /> <script> var app = angular.module("exampleApp",[]); app.controller("parentCtrl",function ($scope) { $scope.data = "Hello,Kobe"; //初始值 $scope.reverseText = function () { $scope.data = $scope.data.split("").reverse().join(""); //将数据分割反转再放进一个数组中 } $scope.changeCase = function () { var result = []; angular.forEach($scope.data.split(""),function (char,index) { result.push(index % 2 == 1 ? char.toString().toUpperCase() : char.toString().toLowerCase()); }); $scope.data = result.join(""); //将奇数字母转小写,偶数字母转大写 }; }); app.controller("firstChildCtrl",function ($scope) { $scope.changeCase = function () { $scope.data = $scope.data.toUpperCase(); //将值转为大写 }; }); app.controller("secondChildCtrl",function ($scope) { $scope.changeCase = function () { $scope.data = $scope.data.toLowerCase(); //将值转为小写 }; $scope.shiftFour = function () { var result = []; angular.forEach($scope.data.split(""),index) { result.push(index < 4 ? char.toUpperCase() : char); }); $scope.data = result.join(""); //将前4字母转为大写,后面的不变 } }); </script> </head> <body ng-controller="parentCtrl"> <div class="well"> <h4>Parent Controller</h4> <div class="input-group"> <span class="input-group-btn"> <button class="btn btn-default" type="button" ng-click="reverseText()">Reverse</button> <button class="btn btn-default" type="button" ng-click="changeCase()">Case</button> </span> <input class="form-control" ng-model="data"> </div> </div> <div class="well" ng-controller="firstChildCtrl"> <h4>First Child Controller</h4> <div class="input-group"> <span class="input-group-btn"> <button class="btn btn-default" type="button" ng-click="reverseText()">Reverse</button> <button class="btn btn-default" type="button" ng-click="changeCase()">Case</button> </span> <input class="form-control" ng-model="data"> </div> </div> <div class="well" ng-controller="secondChildCtrl"> <h4>Second Child Controller</h4> <div class="input-group"> <span class="input-group-btn"> <button class="btn btn-default" type="button" ng-click="reverseText()">Reverse</button> <button class="btn btn-default" type="button" ng-click="changeCase()">Case</button> <button class="btn btn-default" type="button" ng-click="shiftFour()">Shift</button> </span> <input class="form-control" ng-model="data"> </div> </div> </body> </html>
效果:
AngularJS控制器 as 别名
angular在view上的绑定都必须使用直接的scope对象,对于controller来说我们也得必须注入$scope这个service。 angular从1.2版本开始带来了新语法Controller as。如下:<!DOCTYPE html> <html ng-app="exampleApp" > <head> <Meta charset="utf-8"> <title>as别名</title> <link href="bootstrap.css" rel="stylesheet" /> <link href="bootstrap-theme.css" rel="stylesheet" /> <script src="angular.js"></script> <script> var myApp = angular.module("exampleApp",[]); myApp.controller("dayCtrl",function () { this.day = new Date(); }); </script> </head> <body > <div class="panel" ng-controller="dayCtrl as dc"> <div class="page-header"> <h3>AngularJS as 测试</h3> </div> <h4>Now is {{dc.day | date:"yyyy-MM-dd HH:mm:ss"}}</h4> </div> </body> </html>效果:
其实controller的as语法,只是利用了$scope属性。将as后面的别名作为$scope中的对象。Angularjs源码实现如下:
if (directive.controllerAs) { locals.$scope[directive.controllerAs] = controllerInstance; }由此可以看到,controlleras只是$scope对象中的属性。因此,可以通过{{controllerAs.xxx}}访问到controllerInstance中的属性。
AngularJS中的事件传播机制
AngularJS中的作用域有一个非常有层次和嵌套分明的结构。其中它们都有一个主要的$rootScope(也就说对应的Angular应用或者ng-app),然后其他所有的作用域部分都是继承自这个$rootScope的,或者说都是嵌套在主作用域下面的。
那么在作用域之间如何通信呢?其中一个选择就是在应用程序作用域之中创建一个单例服务,然后通过这个服务处理所有子作用域的通信。
在AngularJS中还有另外一个选择:通过作用域中的事件处理通信。不过有所限制,例如,你并不能广泛的将事件传播到所有监控的作用域中。你必须选择是否与父级作用域或者子作用域通信。
$on、$emit和$broadcast使得event、data在controller之间的传递变的简单,关系如下:
那么在作用域之间如何通信呢?其中一个选择就是在应用程序作用域之中创建一个单例服务,然后通过这个服务处理所有子作用域的通信。
在AngularJS中还有另外一个选择:通过作用域中的事件处理通信。不过有所限制,例如,你并不能广泛的将事件传播到所有监控的作用域中。你必须选择是否与父级作用域或者子作用域通信。
$on、$emit和$broadcast使得event、data在controller之间的传递变的简单,关系如下:
- $emit只能向parent controller传递event与data
- $broadcast只能向child controller传递event与data $on用于接收event与data
- $emit和$broadcast可以传多个参数,$on也可以接收多个参数
例子如下:
<!DOCTYPE html> <html ng-app="exampleApp"> <head> <Meta charset="utf-8"> <title>App Event Test</title> <script src="angular.js"></script> <link href="bootstrap.css" rel="stylesheet" /> <link href="bootstrap-theme.css" rel="stylesheet" /> <script> var app =angular.module("exampleApp",[]); app.controller('SelfCtrl',function($scope) { $scope.click = function () { $scope.$broadcast('to-child','child'); $scope.$emit('to-parent','parent'); } }); app.controller('ParentCtrl',function($scope) { $scope.$on('to-parent',function(event,data) { console.log('ParentCtrl',data); //父级能得到值 }); $scope.$on('to-child',data); //子级得不到值 }); }); app.controller('ChildCtrl',function($scope){ $scope.$on('to-child',data) { console.log('ChildCtrl',data); //子级能得到值 }); $scope.$on('to-parent',data); //父级得不到值 }); }); app.controller('BroCtrl',function($scope){ $scope.$on('to-parent',data) { console.log('BroCtrl',data); //平级得不到值 }); $scope.$on('to-child',data); //平级得不到值 }); }); </script> </head> <body > <div ng-controller="ParentCtrl"> <!--父级--> <div ng-controller="SelfCtrl"> <!--自己--> <button type="button" class="btn btn-default" ng-click="click()">click me</button> <div ng-controller="ChildCtrl"></div> <!--子级--> </div> <div ng-controller="BroCtrl"></div> <!--平级--> </div> <br> </body> </html>效果: