angularjs 控制器、做用域、廣播詳解

1、控制器javascript

首先列出幾種咱們日常使用控制器時的幾種誤區:css

咱們知道angualrJs中一個控制器時能夠對應不一樣的視圖模板的,但這種實現方式存在的問題是:html

若是視圖1和視圖2根本沒有任何邏輯關係,這樣「控制器」的角色就會很尷尬,由於咱們不可能把不一樣業務的數據模型都綁在同一個控制器中。java

 

這種實現方式也存在一個問題是:若是控制器1和控制器2裏面有2個方法是如出一轍的怎麼辦?angularjs

 

<!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");
    }
}

雖然子級控制器能夠繼承父級控制器的做用域及方法,可是咱們通常不要去這樣作,由於極可能會形成做用域的混亂。瀏覽器

 

正確的方式應該是這樣的:咱們把公共的方法抽離出來,放在公共的服務當中去,須要的時候從公共的服務中調取就行了。app

 

在使用控制器時要注意幾點:工具

1.不要去複用controller,一個控制器通常只負責一小塊視圖;(通常控制器處理的都是業務邏輯,業務邏輯的複用性通常很小)spa

2.不要在controller中操做DOM,這不是控制器的職責;(由於在 controller裏面操做DOM會致使瀏覽器頁面的重繪,這種代價是昂貴的)3d

3.通常不要在控制器裏面作數據過濾操做,ng有$filter服務;

通常來講,Controller是不會相互調用的,控制器之間的交互會經過廣播事件進行!

 

2、做用域

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、廣播

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); }); }]);
相關文章
相關標籤/搜索