一、控制器 首先列出幾種我們平常使用控制器時的幾種誤區: 我們知道angualrJs中一個控制器時可以對應不同的視圖模板的,但這種實現方式存在的問題是: 如果視圖1和視圖2根本沒有任何邏輯關係,這樣“控制器”的角色就會很尷尬,因為我們不可能把不同業務的數據模型都綁在同一個控制器中。 這種實現方式也存 ...
一、控制器
首先列出幾種我們平常使用控制器時的幾種誤區:
我們知道angualrJs中一個控制器時可以對應不同的視圖模板的,但這種實現方式存在的問題是:
如果視圖1和視圖2根本沒有任何邏輯關係,這樣“控制器”的角色就會很尷尬,因為我們不可能把不同業務的數據模型都綁在同一個控制器中。
這種實現方式也存在一個問題是:如果控制器1和控制器2裡面有2個方法是一模一樣的怎麼辦?
<!doctype html> <html ng-app> <head> <meta charset="utf-8"> </head> <body> <div ng-controller="CommonController"> <div ng-controller="Controller1"> <p>{{greeting.text}},Angular</p> <button ng-click="test1()">test1</button> </div> <div ng-controller="Controller2"> <p>{{greeting.text}},Angular</p> <button ng-click="test2()">test2</button> <button ng-click="commonFn()">通用</button> </div> </div> </body> <script src="js/angular-1.3.0.js"></script> <script src="MVC3.js"></script> </html>
function CommonController($scope){ $scope.commonFn=function(){ alert("這裡是通用功能!"); }; } function Controller1($scope) { $scope.greeting = { text: 'Hello1' }; $scope.test1=function(){ alert("test1"); }; } function Controller2($scope) { $scope.greeting = { text: 'Hello2' }; $scope.test2=function(){ alert("test2"); } }
雖然子級控制器可以繼承父級控制器的作用域及方法,但是我們一般不要去這樣做,因為很可能會造成作用域的混亂。
正確的方式應該是這樣的:我們把公共的方法抽離出來,放在公共的服務當中去,需要的時候從公共的服務中調取就好了。
在使用控制器時要註意幾點:
1.不要去復用controller,一個控制器一般只負責一小塊視圖;(一般控制器處理的都是業務邏輯,業務邏輯的復用性一般很小)
2.不要在controller中操作DOM,這不是控制器的職責;(因為在 controller裡面操作DOM會導致瀏覽器頁面的重繪,這種代價是昂貴的)
3.一般不要在控制器裡面做數據過濾操作,ng有$filter服務;
一般來說,Controller是不會相互調用的,控制器之間的交互會通過廣播事件進行!
二、作用域
angularJs的MVC是藉助$scope來實現的!
先來看一段代碼:
<!doctype html> <html ng-app> <head> <meta charset="utf-8"> <link rel="stylesheet" type="text/css" href="Scope1.css" /> </head> <body> <div class="show-scope-demo"> <div ng-controller="GreetCtrl"> Hello {{name}}! </div> <div ng-controller="ListCtrl"> <ol> <li ng-repeat="name in names"> {{name}} from {{department}} </li> </ol> </div> </div> </body> <script src="js/angular-1.3.0.js"></script> <script src="Scope1.js"></script> </html>
function GreetCtrl($scope, $rootScope) { $scope.name = 'World'; $rootScope.department = 'Angular'; } function ListCtrl($scope) { $scope.names = ['Igor', 'Misko', 'Vojta']; }
上面是兩個不同的控制器,儘管ListCtrl控制器裡面沒有department,但它依然可以訪問到department上的變數值。
神奇的$scope
1.$scope是一個對象;
2.$scope是表達式的執行環境(或者叫做作用域)(它是視圖和控制器之間的膠水);
3.$scope提供了一些工具方法$watch()/$apply();
(這個是實時檢測對象屬性變化的,在修改數據時會立刻更新$scope,當$scope發生變化時會立刻重新渲染視圖);
(這兩個方法雖然提供了監視數據模型變化的能力,將數據模型的變化在整個應用範圍內進行通知,但一般我們不太會手動去調用$scope.$apply())
4.$scope是一個樹形結構,與DOM標簽平行;
5.子$scope會繼承父$scope上的屬性和方法;
6.每個angularJs應用只有一個$rootScope,一般位於ng-app上,$rootScope是所有$scope的最上層,
($rootScope也是angularJs中最接近全局作用域的對象,在$rootScope上附加太多業務邏輯並不是好主意,這與污染javaScript的全局作用域是一樣的)
7.$scope也是實現雙向數據綁定的基礎;
8.可以用angular.element($0).scope()來進行調試;
9.$scope可以在控制器之間傳播事件,可以向上$scope.$emit();也可以向下$scooe.$broadcast();
最後附一張$scope的生命周期圖:
創建(創建一個作用域)——鏈接($scope對象會鏈接到視圖中)——更新(臟值檢查)——銷毀(銷毀作用域)
三、廣播
3.1相關概念
通常作用域之間是不共用變數的,但作用域是有層次的,所以我們可以在作用域上通過廣播來傳遞事件。
Angularjs中不同作用域之間可以通過組合使用$emit,$broadcast,,$on的事件廣播機制來進行通信
$emit的作用是將事件從子級作用域傳播至父級作用域,包括自己,直至根作用域。格式如下:$emit(eventName,args)
$broadcast的作用是將事件從父級作用域傳播至子級作用域,包括自己。格式如下:$broadcast(eventName,args)
$on用於在作用域中監控從子級或父級作用域中傳播的事件以及相應的數據。格式如下:$on(event,data)
上述說明中,eventName是需要廣播的事件的名稱,args傳遞的數據集合,$on 方法中的參數event是事件的相關對象,data是事件傳播的數據。
3.2實例說明angularjs $emit $broadcast $on
的用法
<div ng-controller="ParentCtrl"> <div ng-controller="SelfCtrl"> <a ng-click="click()">click</a> <div ng-controller="ChildCtrl"></div> </div> <div ng-controller="BroCtrl"></div> </div>
var appControllers = angular.module('myApp', []) appControllers.controller('SelfCtrl', ['$scope','$rootScope', function($scope, $rootScope){ var admin1 = { 'name': 'father', 'age': 45 }; var admin2 = { 'name': 'Lucy', 'age': 25 }; $scope.click = function() { //事件的發送 //向子級控制器傳遞數據和事件,只有ChildCtrl能接受到廣播,還有自己 $scope.$broadcast('to-child', admin2); //向父級控制器傳遞數據和事件,只有parentCtrl能接收到廣播,還有自己 $scope.$emit('to-parent', admin1); //$rootScope發出的廣播所有的作用域都可以接受到,可以用於同級之間進行廣播 $rootScope.$broadcast('to-bro', '平級的數據'); } }])
appControllers.controller('ParentCtrl', ['$scope', '$rootScope', function($scope, $rootScope){ //事件的接受 $scope.$on('to-parent', function(event, data){ console.log(event); }); }])
appControllers.controller('ChildCtrl', ['$scope', '$rootScope', function($scope, $rootScope){ $scope.$on('to-child', function(event, data){ console.log(data); }); }])
appControllers.controller('BroCtrl', ['$scope', '$rootScope', function($scope, $rootScope){ //$scope和$rootScope都可以接受到事件 $scope.$on('to-bro', function(event, data){ console.log(data); }); $rootScope.$on('to-bro', function(event, data){ console.log(data); }); }]);