在AngularJS中,控制器是一個(gè)Javascript函數(shù)(類型/類),用來(lái)增強(qiáng)除了根作用域意外的作用域?qū)嵗?。?dāng)你或者AngularJS本身通過(guò)scope.$new
倆創(chuàng)建一個(gè)新的子作用域?qū)ο髸r(shí),有一個(gè)選項(xiàng)能讓你將它當(dāng)做參數(shù)傳遞給控制器。這能使AngularjS將控制器和這個(gè)作用域聯(lián)系起來(lái),增強(qiáng)作用域的行為。
控制器用于:
一般來(lái)說(shuō),當(dāng)你創(chuàng)建應(yīng)用時(shí),你需要對(duì)它的作用域設(shè)置初始狀態(tài)。
AngularJS將對(duì)作用域?qū)ο笳{(diào)用控制器的構(gòu)造函數(shù)(從某種意義上來(lái)說(shuō)就像使用的Javascript的apply方法),以此來(lái)設(shè)置作用域的初始狀態(tài)。這意味著AngularJS不會(huì)創(chuàng)建控制器類型的實(shí)例(不會(huì)使用new方法來(lái)調(diào)用控制器構(gòu)造函數(shù))??刂破骺偸菍?duì)某個(gè)已存在的作用域?qū)ο笳{(diào)用。formatDate
你可以通過(guò)創(chuàng)建一個(gè)模型屬性來(lái)設(shè)置初始作用域的初始狀態(tài)。 比如:
function GreetingCtrl($scope) { $scope.greeting = 'Hola!'; }
GreetingCtrl控制器創(chuàng)建了一個(gè)模板中可以調(diào)用的叫greeting
的模型。
AngularJS作用域?qū)ο蟮男袨槭怯勺饔糜虻姆椒▉?lái)表示的。這些方法是可以在模板或者說(shuō)視圖中調(diào)用的。這些方法和應(yīng)用模型交互,并且能改變模型。
如我們?cè)谀P湍且徽滤f(shuō)的,任何對(duì)象(或者原生的類型)被賦給作用域后就會(huì)變成模型。任何賦給作用域的方法,都能在模板或者說(shuō)視圖中被調(diào)用,并且能通過(guò)表達(dá)式或者ng
事件指令調(diào)用。(比如,ngClick)
總的來(lái)說(shuō),一個(gè)控制器不應(yīng)該做太多工作。它應(yīng)該只包含單個(gè)視圖的業(yè)務(wù)邏輯。
保持控制器職責(zé)單一的最常見做法是將那些不屬于控制器的工作抽離到服務(wù)中,然后通過(guò)依賴注入在控制器中使用這些服務(wù)。這在依賴注入服務(wù)的章節(jié)中會(huì)詳細(xì)討論。
不要用控制器干下面的事情:
dev_guide.templates.databinding
用來(lái)自動(dòng)進(jìn)行DOM操作。如果你需要手動(dòng)操作DOM,將表現(xiàn)層的邏輯抽離到指令中。你可以顯示地用scope.$new
來(lái)將控制器和作用域?qū)ο箫@示地聯(lián)系起來(lái),或者隱式地通過(guò)ngController
指令或者$route
服務(wù)來(lái)聯(lián)系。
為了闡述AngularJS的控制器組件的運(yùn)行原理,讓我們來(lái)創(chuàng)建一個(gè)擁有下面這些組件的小應(yīng)用:
spice
的字符串模型。spice
的值得。模板中的消息包含了一個(gè)對(duì)spice
模型的綁定,它初始的字符串是“very”。這個(gè)spice模型會(huì)被設(shè)置成 chili 或者 jalapeno,這取決于哪個(gè)按鈕會(huì)被點(diǎn)擊。消息會(huì)通過(guò)data-binding
自動(dòng)更新。
<body ng-controller="SpicyCtrl"> <button ng-click="chiliSpicy()">Chili</button> <button ng-click="jalapenoSpicy()">Jalape?o</button> <p>The food is {{spice}} spicy!</p></body>function SpicyCtrl($scope) { $scope.spice = 'very'; $scope.chiliSpicy = function() { $scope.spice = 'chili'; } $scope.jalapenoSpicy = function() { $scope.spice = 'jalape?o'; }}
例子中有下面這些需要注意:
ngController
指令是用來(lái)(隱式地)為模板創(chuàng)建作用域的。并且使用命令中指定的spicyCtrl
控制器來(lái)增強(qiáng)這個(gè)作用域。spicyCtrl
只是一個(gè)純Javascript函數(shù)。使用了駝峰式命名法(可選)命名并以Ctrl或者Controller結(jié)尾。chiliSpicy
方法)。控制器方法可以接受參數(shù),像下面里中演示的:
<body ng-controller="SpicyCtrl"> <input ng-model="customSpice" value="wasabi"> <button ng-click="spicy('chili')">Chili</button> <button ng-click="spicy(customSpice)">Custom spice</button> <p>The food is {{spice}} spicy!</p></body>function SpicyCtrl($scope) { $scope.spice = 'very'; $scope.spicy = function(spice) { $scope.spice = spice; }}
注意SpicyCtrl
控制器只定義了一個(gè)叫spicy的方法,它接受一個(gè)叫做spice的參數(shù)。和這個(gè)控制器相關(guān)的模板在第一個(gè)按鈕事件中傳遞了一個(gè)chili
常量給控制器方法,在第二個(gè)按鈕中傳遞一個(gè)模型屬性。
AngularJS中的控制器繼承是基于作用域的繼承的。讓我們看下面這個(gè)例子:
<body ng-controller="MainCtrl"> <p>Good {{timeOfDay}}, {{name}}!</p> <div ng-controller="ChildCtrl"> <p>Good {{timeOfDay}}, {{name}}!</p> <p ng-controller="BabyCtrl">Good {{timeOfDay}}, {{name}}!</p></body>function MainCtrl($scope) { $scope.timeOfDay = 'morning'; $scope.name = 'Nikki';}function ChildCtrl($scope) { $scope.name = 'Mattie';}function BabyCtrl($scope) { $scope.timeOfDay = 'evening'; $scope.name = 'Gingerbreak Baby';}
注意我們是如何在模板中嵌套我們的ngController
指令的。這個(gè)模板結(jié)構(gòu)會(huì)使得AngularJS為視圖創(chuàng)建四個(gè)作用域:
控制器的繼承和模型繼承是同一個(gè)原理。所以在我們前面的例子中,所有的模型都用返回相應(yīng)字符串的控制器方法代替。
注意:常規(guī)的原型繼承對(duì)控制器來(lái)說(shuō)不起作用。因?yàn)檎缥覀冎疤岬降模刂破鞑皇侵苯訉?shí)例化的,而是對(duì)作用域?qū)ο笳{(diào)用的。
盡管有很多測(cè)試控制器的方法。但最好的是像我們下面這樣展示的。這個(gè)例子注入了$rootScope和$controller。
控制器函數(shù):
function myController($scope) { $scope.spices = [{"name":"pasilla", "spiciness":"mild"}, {"name":"jalapeno", "spiceiness":"hot hot hot!"}, {"name":"habanero", "spiceness":"LAVA HOT!!"}]; $scope.spice = "habanero";}
控制器測(cè)試:
describe('myController function', function() { describe('myController', function() { var scope; beforeEach(inject(function($rootScope, $controller) { scope = $rootScope.$new(); var ctrl = $controller(myController, {$scope: scope}); })); it('should create "spices" model with 3 spices', function() { expect(scope.spices.length).toBe(3); }); it('should set the default value of spice', function() { expect(scope.spice).toBe('habanero'); }); });});
如果你需要測(cè)試嵌套的控制器,你需要?jiǎng)?chuàng)建和DOM中相同相同的作用域?qū)蛹?jí)。
describe('state', function() { var mainScope, childScope, babyScope; beforeEach(inject(function($rootScope, $controller) { mainScope = $rootScope.$new(); var mainCtrl = $controller(MainCtrl, {$scope: mainScope}); childScope = mainScope.$new(); var childCtrl = $controller(ChildCtrl, {$scope: childScope}); babyScope = childCtrl.$new(); var babyCtrl = $controller(BabyCtrl, {$scope: babyScope}); })); it('should have over and selected', function() { expect(mainScope.timeOfDay).toBe('morning'); expect(mainScope.name).toBe('Nikki'); expect(childScope.timeOfDay).toBe('morning'); expect(childScope.name).toBe('Mattie'); expect(babyScope.timeOfDay).toBe('evening'); expect(babyScope.name).toBe('Gingerbreak Baby'); });});
聯(lián)系客服