AngularJS兄弟控制器如何通信?点击按钮同步更新视图
问题:AngularJS点击按钮让不同控制器显示对应消息,是否只能用$on/$broadcast实现?
我现有如下AngularJS代码(HTML部分):
<div ng-controller="mainCtrl"> <button ng-click="onclick()"></button> <button ng-click="onclick()"></button> <button ng-click="onclick()"></button> {{display}} </div> <div ng-controller="SecondController">{{display}}</div> <div ng-controller="lastController">{{display}}</div>
需求是:用户点击按钮时,每个控制器对应的div中显示对应消息。我尝试了以下JS代码:
app.controller('mainCtrl',function($scope,$rootScope){ $scope.OnClick = function (msg) { $rootScope.$broadcast("firstEvent",{}); } $scope.$on("firstEvent", function (msg ) { $scope.display = "hello world"; }); }); app.controller('SecondController',function( $scope){ $scope.$on("firstEvent", function (msg) { $scope.display = "hello how Are you"; }); }); app.controller('lastController',function($scope) { $scope.$on("firstEvent", function (msg) { $scope.display = "this is my Query"; }); });
现在想实现点击按钮时各个div显示对应数据,请问是否只能通过$on、$broadcast实现该功能?
回答
其实不是只能用事件广播这种方式哦,AngularJS里还有几种更优雅(或者更适合不同场景)的方案,我给你一一说明:
1. 使用共享服务(最推荐的方案)
AngularJS的服务是单例模式,所有控制器都可以注入同一个服务实例,通过服务来管理共享状态,这种方式更符合模块化思想,也更容易维护。
示例代码:
// 先定义一个共享服务 app.service('MessageService', function() { this.messages = { main: '', second: '', last: '' }; this.updateMessages = function() { this.messages.main = "hello world"; this.messages.second = "hello how Are you"; this.messages.last = "this is my Query"; }; }); // 各个控制器注入服务并绑定数据 app.controller('mainCtrl',function($scope, MessageService){ $scope.display = MessageService.messages.main; $scope.onclick = function () { MessageService.updateMessages(); // 因为AngularJS的双向绑定,服务更新后视图会自动同步 $scope.display = MessageService.messages.main; }; }); app.controller('SecondController',function( $scope, MessageService){ $scope.$watch(function() { return MessageService.messages.second; }, function(newVal) { $scope.display = newVal; }); }); app.controller('lastController',function($scope, MessageService) { $scope.$watch(function() { return MessageService.messages.last; }, function(newVal) { $scope.display = newVal; }); });
2. 直接使用$rootScope(不推荐,仅作了解)
你已经用到了$rootScope,其实可以直接在$rootScope上定义共享变量,子控制器的$scope会继承$rootScope的属性。不过这种方式会造成全局作用域污染,复杂应用里很容易出问题,所以不推荐。
示例代码:
app.controller('mainCtrl',function($scope,$rootScope){ $scope.onclick = function () { $rootScope.mainDisplay = "hello world"; $rootScope.secondDisplay = "hello how Are you"; $rootScope.lastDisplay = "this is my Query"; }; }); app.controller('SecondController',function( $scope){ $scope.display = $scope.secondDisplay; }); app.controller('lastController',function($scope) { $scope.display = $scope.lastDisplay; });
然后HTML里对应修改绑定:
<div ng-controller="mainCtrl"> <button ng-click="onclick()"></button> {{mainDisplay}} </div> <div ng-controller="SecondController">{{secondDisplay}}</div> <div ng-controller="lastController">{{lastDisplay}}</div>
3. 优化你原来的事件广播方案
另外,你的现有代码有个小问题:按钮上的ng-click="onclick()"和控制器里的$scope.OnClick大小写不匹配,所以点击事件不会触发。修正后这个方案是可以正常工作的,而且广播时还可以传递数据,不用每个控制器硬编码消息:
app.controller('mainCtrl',function($scope,$rootScope){ // 修正函数名大小写 $scope.onclick = function () { // 广播时可以传递消息数据 $rootScope.$broadcast("firstEvent", { mainMsg: "hello world", secondMsg: "hello how Are you", lastMsg: "this is my Query" }); } $scope.$on("firstEvent", function (event, data ) { $scope.display = data.mainMsg; }); }); app.controller('SecondController',function( $scope){ $scope.$on("firstEvent", function (event, data) { $scope.display = data.secondMsg; }); }); app.controller('lastController',function($scope) { $scope.$on("firstEvent", function (event, data) { $scope.display = data.lastMsg; }); });
总结一下:事件广播是可行的实现方式,但绝对不是唯一的。共享服务是最推荐的方案,因为它更符合AngularJS的设计理念,代码也更易于维护和扩展。
内容的提问来源于stack exchange,提问作者ronaldino
相关产品推荐
相关产品推荐

