angularjs中controller之間的通信

不同框架實現(xiàn)的功能都是相似的,只不過方法不同,這就為我們了解不同框架,從一個框架向另一個框架學(xué)習(xí)提供了方便。比如說頁面之間的傳值,看了vuex之后就在想angular實現(xiàn)類似的功能應(yīng)該怎么做。
在angular中,實現(xiàn)controller之間傳值的方式大致有三種:

  • 注入服務(wù)。把需要共享的數(shù)據(jù)注冊為一個service,在需要的controller中注入。
  • 基于事件。利用angular中的事件機制,使用$on,$boardcast,$emit。
  • 作用域繼承。利用子controller控制父controller上的數(shù)據(jù)。

在大項目中應(yīng)該使用注入服務(wù)(推薦),小項目中可以使用基于事件的傳值(事件多了很繁瑣,不利于高內(nèi)聚、低耦合),作用域繼承不推薦(很大的局限性)。

注入服務(wù)

在Angular里面,services作為單例對象在需要到的時候被創(chuàng)建,只有在應(yīng)用生命周期結(jié)束的時候(關(guān)閉瀏覽器)才會被清除。而controllers在不需要的時候就會被銷毀了。所以在服務(wù)中生成一個對象,該對象就可以利用依賴注入的方式在所有的控制器中共享。

看個栗子,先定義一個 service :

angular.module('demo')
    .factory('Data', function(){
        return {
            name: 'htf'
        };
    })

頁面:

<div ng-controller="childCtrl1">
  <h3>data in child controller 1 : {{data.name}}</h3>
  <input class="form-control" type="text" ng-model="data.name">
</div>
<div ng-controller="childCtrl2">
  <h3>data in child controller 2 : {{data.name}}</h3>
  <input class="form-control" type="text" ng-model="data.name">
</div>

控制器:

.controller('childCtrl1', ['$scope', 'Data', function($scope, Data){
    $scope.data = Data;
}])

.controller('childCtrl2', ['$scope', 'Data', function($scope, Data){
    $scope.data = Data;
}])

這種方式適用于任何需要通信的 Controller 之間。

基于事件

Angular 為 $scope 提供了冒泡和隧道機制,$broadcast 會把事件廣播給所有子 Controller,而 $emit 則會將事件冒泡傳遞給父 Controller,$on 則是 Angular 的事件監(jiān)聽函數(shù),利用這三者,可以實現(xiàn)上下級和同級(需要構(gòu)造一個共同的父級 Controller)之間的通信。

上下級之間

這種情況下比較簡單。

如果是子 Controller 往父 Controller 上發(fā)送事件(從作用域往上發(fā)送事件),使用 scope.$emit

$scope.$emit("someEvent", {});

如果是父 Controller 往子 Controller 上發(fā)送事件(從作用域往下發(fā)送事件),使用 scope.$broadcast

$scope.$broadcast("someEvent", {});

無論是 $emit 還是 $broadcast 發(fā)送的事件,都用 $scope.$on 接收:

$scope.$on("someEvent", function(event, data) {
    // 這里取到發(fā)送過來的數(shù)據(jù) data
});

同級之間

同級之間利用事件通信有兩種方法。一種是利用上下級之間事件傳播的變形,另一種是借助 $rootScope 。

借助父 controller

先看第一種,在子 Controller 中向父 Controller 觸發(fā)一個事件,然后在父 Controller 中監(jiān)聽事件,再廣播給子 Controller ,這樣通過事件攜帶的參數(shù),實現(xiàn)了數(shù)據(jù)經(jīng)過父 Controller,在同級 Controller 之間傳播。

但是要注意,通過父 Controller 作為中介進行傳遞的話,子 Controller 觸發(fā)的事件名和父 Controller 廣播用的事件名不能一樣,否則會進入死循環(huán)。

看代碼:

<div ng-controller="outerCtrl">
  <h3>data in outer controller: {{name}}</h3>
  <div ng-controller="innerCtrl1">
    <input class="form-control" type="text" ng-model="name" ng-change="change()">
  </div>
  <div ng-controller="innerCtrl2">
    <input class="form-control" type="text" ng-model="name" ng-change="change()">
  </div>
</div>

關(guān)鍵部分在控制器:

.controller('outerCtrl', ['$scope', function($scope){
    $scope.name = 'htf';
    $scope.$on('dataChanged', function(event, data){
        $scope.name = data;
        // 2. 父 Ctrl 監(jiān)聽到 dataChanged 時間后,觸發(fā) changeData 事件
        $scope.$broadcast('changeData', data);
    })
}])

.controller('innerCtrl1', ['$scope', function($scope){
    $scope.change = function(){
        // 1. 子 Ctrl1 中數(shù)據(jù)改變之后觸發(fā) dataChanged 事件
        $scope.$emit('dataChanged', $scope.name);
    }
    $scope.$on('changeData', function(event, data){
        $scope.name = data;
    })
}])

.controller('innerCtrl2', ['$scope', function($scope){
    $scope.change = function(){
        $scope.$emit('dataChanged', $scope.name);
    }
    // 3. 監(jiān)聽到 changeData 事件后,改變子 Ctrl2 中 數(shù)據(jù)
    $scope.$on('changeData', function(event, data){
        $scope.name = data;
    })
}])

借助 $rootScope

每個 Angular 應(yīng)用默認(rèn)有一個根作用域 $rootScope, 根作用域位于最頂層,從它往下掛著各級作用域。

所以,如果子控制器直接使用 $rootScope 廣播和接收事件,那么就可實現(xiàn)同級之間的通信。

看栗子:

<div ng-controller="innerCtrlA">
    <input class="form-control" type="text" ng-model="name" ng-change="change()">
</div>
<div ng-controller="innerCtrlB">
    <input class="form-control" type="text" ng-model="name" ng-change="change()">
</div>

控制器:

.controller('innerCtrlA', ['$scope', '$rootScope', function($scope, $rootScope){
    $scope.change = function(){
        // 廣播事件
        $rootScope.$broadcast('nameChanged', $scope.name);
    }
    $rootScope.$on('nameChanged', function(event, data){
        $scope.name = data;
    })
}])

.controller('innerCtrlB', ['$scope', '$rootScope', function($scope, $rootScope){
    $scope.change = function(){
        $rootScope.$broadcast('nameChanged', $scope.name);
    }
    // 監(jiān)聽事件
    $rootScope.$on('nameChanged', function(event, data){
        $scope.name = data;
    })
}])

作用域繼承

每個 Angular 應(yīng)用默認(rèn)有一個根作用域 $rootScope, 根作用域位于最頂層,從它往下掛著各級作用域。

通常情況下,頁面中 ng-model 綁定的變量都是在對應(yīng)的 Controller 中定義的。如果一個變量未在當(dāng)前作用域中定義,JavaScript 會通過當(dāng)前 Controller 的 prototype 向上查找,也就是作用域的繼承。

頁面:

<div ng-controller="parentCtrl">
  <p>data in parent controller : {{data.name}}</p>
  <div ng-controller="childCtrl">
    <input type="text" ng-model="data.name">
  </div>
</div>

控制器:

angular.module('demo', [])

.controller('parentCtrl', ['$scope', function($scope){
    $scope.data = {
        name: 'htf'
    }
}])

.controller('childCtrl', ['$scope', function($scope){

}])

以上是父 Controller 中的數(shù)據(jù)是引用類型的情況。如果父 Controller 中的數(shù)據(jù)是基本類型,改變子controller的值父controller的值不變,可通過 $scope.$parent.data 訪問。

很顯然,這種方式僅適用于父子級間 Controller 的通信。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1.類庫( 提供類方法 ) 和框架 類庫提供一系列的函數(shù)和方法的合集,能夠加快你寫代碼的速度。但是主導(dǎo)邏輯的還是自...
    w_zhuan閱讀 1,947評論 0 8
  • 這是一個面試官問我的題目,當(dāng)時沒回答出來,主要是項目中沒有碰到過這類問題,因此今天整理下查找到的資料,希望對大家有...
    一木_qintb閱讀 780評論 0 2
  • Angular面試題 一、ng-show/ng-hide與ng-if的區(qū)別? 第一點區(qū)別是,ng-if在后面表達式...
    w_zhuan閱讀 5,705評論 0 26
  • 1、angularjs的幾大特性是什么? 雙向數(shù)據(jù)綁定、依賴注入、模板、指令、MVC/MVVM 2、列舉幾種常見的...
    2e9a10d418ab閱讀 1,462評論 0 10
  • 總覺得我是在書里長大的孩子。 從小就愛看書,除了那些兒時大家一起玩鬧的游戲之外,我個人的最大愛好就是兩件事了:看書...
    小小小小只閱讀 229評論 0 1

友情鏈接更多精彩內(nèi)容