AngularJS開發學習筆記:父子作用域之間的通信—$on、 $emit、$broadcast的介紹

angularJs中的作用域($scope)結構和DOM結構非常相似,也是一個層次分明的樹狀結構。它有一個根作用域$rootscope(對應angular應用或ng-app),其他作用域是嵌套在根作用域下面的。 


angularJs的$scope之間都遵循js中對象原型繼承方式,當子作用域中沒有該對象時,默認向上級作用域(父作用域)尋找,直到找到或者到達$rootscope爲止,當子作用域有該對象時,使用子作用域中的對象。

注:這裏的父作用域包含直接父級和祖先,子作用域包含直接子級和更下層級 


例子如下:

<body ng-app="myApp">
    <div ng-controller="fatherCtrl">
        <input type="text" ng-model="name" ng-change="nameOnChange()">
        <h1>Father: {{name}}!</h1>
        <div ng-controller="sonCtrl">
             <input type="text" ng-model="name" ng-change="nameOnChange()"> 
             <h1>Son: {{name}}</h1>
        </div>
    </div>
</body>


其中fatherCtrl 和 sonCtrl 裏都使用了 name,但sonCtrl中並沒有定義name。

var app = angular.module ('myApp', []);
    app.controller('fatherCtrl', function ($scope) {
        $scope.name = "father";
        $scope.$watch("name",function () {
            console.log("fatherScope:"+$scope.name)
        })

    });
    app.controller('sonCtrl', function ($scope) {
        $scope.$watch("name",function () {
            console.log("sonScope:"+$scope.name)
        })
    });


這時sonCtrl 直接讀取 fatherCtrl 中的 name,改變fatherCtrl中name的值,sonCtrl顯示的值也會同步改變。

效果如圖:


但當通過view同步改變sonCtrl中name的值時,sonCtrl中會重新創建一個name的對象,faterCtrl中的值不會改變。 


效果如圖:

è¿éåå¾çæè¿°

如何在作用域之間通信呢? 
1.創建一個單例服務,然後通過這個服務處理所有子作用域的通信。 
2.通過作用域中的事件處理通信。但是這種方法有一些限制;你並不能廣泛的將事件傳播到所有監控的作用域中。你必須選擇是與父級作用域或者子作用域通信。 


$on、$emit和$broadcast使得event、data在controller之間的傳遞變的簡單。 


1、$emit:子傳父,傳遞event與data;

$scope.$emit('name', 'args');


2、$broadcast:父傳子,傳遞event與data;

$scope.$broadcast('name', 'args');


3、$on:監聽或接收數據,用於接收event與data;

$scope.$on('name', function(event,data){});


$broadcast、$emit事件必須依靠其他事件(ng-click等)進行觸發。

值得注意的是:以上事件的主語是 $scope, 因爲所有的事件其實都是作用在scope上的。 


在$on的方法中的event事件參數,其對象的屬性和方法如下:

事件屬性/方法 功能性說明
event.targetScope 獲取傳播事件的作用域
event.currentScope 獲取接收事件的作用域
event.name  傳播的事件的名稱
event.stopPropagation()  阻止事件進行冒泡傳播,僅在$emit事件中有效
event.preventDefault()   阻止默認事件的發生
event.defaultPrevented 如果調用了preventDefault事件則返回true

    


    
    
   
   
 
    

 

 

事件傳播的方向如下圖:

è¿éåå¾çæè¿°


1、$emit 
該服務貫穿作用域發出一個向上的事件,該事件的生命週期開始於emit被啓動的地方,事件一直朝着根作用域傳遞,傳遞期間會通知那些註冊在作用域上的監聽器,在這期間,作用域中的監聽器接收到通知,獲取事件,但是不會註銷事件,事件繼續往下傳播。 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<body ng-app="myApp">
<div ng-controller="fatherCtrl">
    <!--fatherCtrl可以得到-->
    <input type="text" ng-model="name" ng-change="nameOnChange()">
    <h1>Father: {{name}}!</h1>
    <div ng-controller="sonCtrl">
        <!--sonCtrl可以得到-->
        <input type="text" ng-model="name" ng-change="nameOnChange()">
        <h1>Son: {{name}}</h1>
        <div ng-controller="innerCtrl">
            <input type="text" ng-model="name" ng-change="nameOnChange()">
            <h1>inner: {{name}}</h1>
        </div>
    </div>
    <div ng-controller="broCtrl">
        <!--broCtrl得不到-->
        <input type="text" ng-model="name" ng-change="nameOnChange()">
        <h1>brother: {{name}}</h1>
    </div>
</div>

<script>
    var app = angular.module('myApp', []);
    app.controller('fatherCtrl', function ($scope) {
        $scope.name = "father";
        $scope.$on('test', function (e, newName) {
            $scope.name = newName;
        });
    });
    app.controller('sonCtrl', function ($scope) {
        $scope.name = "son";
        $scope.$on('test', function (e, newName) {
            $scope.name = newName;
        });
    });
    app.controller('broCtrl', function ($scope) {
        $scope.name = "brother";
        $scope.$on('test', function (e, newName) {
            $scope.name = newName;
        });
    });
    app.controller('innerCtrl', function ($scope) {
        $scope.name = "inner";
        $scope.nameOnChange = function () {
            $scope.$emit('test', $scope.name);
        }
    });
</script>
</body>


</html>

效果如下:

è¿éåå¾çæè¿°

 

2、$broadcast 
該服務發佈一個向下的事件給作用域中的所有子節點,該事件的生命週期也是從broadcast被啓動開始。下面的所有子作用域都會接收到通知。之後,事件向下傳播,在這期間,作用域中的監聽器接收到通知,獲取事件,但是不會註銷事件,事件繼續往下傳播。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<body ng-app="myApp">
<div ng-controller="fatherCtrl">
    <!--fatherCtrl得不到-->
    <input type="text" ng-model="name" ng-change="nameOnChange()">
    <h1>Father: {{name}}!</h1>
    <div ng-controller="sonCtrl">
        <input type="text" ng-model="name" ng-change="nameOnChange()">
        <h1>Son: {{name}}</h1>
        <div ng-controller="outCtrl">
            <!--outCtrl可以得到-->
            <input type="text" ng-model="name" ng-change="nameOnChange()">
            <h1>out in son: {{name}}</h1>
            <div ng-controller="innerCtrl">
                <!--innerCtrl可以得到-->
                <input type="text" ng-model="name" ng-change="nameOnChange()">
                <h1>inner in out: {{name}}</h1>
            </div>
        </div>
    </div>
    <div ng-controller="broCtrl">
        <!--broCtrl得不到-->
        <input type="text" ng-model="name" ng-change="nameOnChange()">
        <h1>brother: {{name}}</h1>
    </div>
</div>

<script>
    var app = angular.module('myApp', []);
    app.controller('fatherCtrl', function ($scope) {
        $scope.name = "father";
        $scope.$on('test', function (e, newName) {
            $scope.name = newName;
        });
    });
    app.controller('sonCtrl', function ($scope) {
        $scope.name = "son";
        $scope.nameOnChange = function () {
            $scope.$broadcast('test', $scope.name);
        }
    });
    app.controller('broCtrl', function ($scope) {
        $scope.name = "brother";
        $scope.$on('test', function (e, newName) {
            $scope.name = newName;
        });
    });
    app.controller('innerCtrl', function ($scope) {
        $scope.name = "inner";
        $scope.$on('test', function (e, newName) {
            $scope.name = newName;
        });
    });
    app.controller('outCtrl', function ($scope) {
        $scope.name = "out";
        $scope.$on('test', function (e, newName) {
            $scope.name = newName;
        });
    });
</script>
</body>


</html>

 

效果如圖:

è¿éåå¾çæè¿°

 

3、$on 
該服務監聽指定類型的事件,獲取從emit或者broadcast發佈的事件。 


注: 
1、如果在作用域中沒有父子關係存在,可以在控制器中注入$rootScope、使用$broadcast服務向下傳播事件(但這個慎用),但是不能通過$emit向上傳播事件。

2、在作用域中存在父子關係時,可以也僅可以由子控制器使用$emit服務向上傳播事件,同時父作用域中的控制監聽器可以註銷事件。
————————————————
版權聲明:本文爲CSDN博主「冰雪_318」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/lhj20084720208/article/details/78997015

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章