$on 和 $broadcast 的角度

IT技术 javascript angularjs
2021-01-23 16:55:13

我有一个具有不同视图的 footerController 和 codeScannerController。

angular.module('myApp').controller('footerController', ["$scope", function($scope) {}]);

angular.module('myApp').controller('codeScannerController', ["$scope", function($scope) {
console.log("start");
$scope.startScanner = function(){...

当我点击<li>footer.html 中的a 时,我应该在codeScannerController 中得到这个事件。

<li class="button" ng-click="startScanner()">3</li>

我认为它可以用$onand实现$broadcast,但我不知道如何也无法在任何地方找到示例。

4个回答

如果你想$broadcast使用$rootScope

$scope.startScanner = function() {

    $rootScope.$broadcast('scanner-started');
}

然后接收,使用$scope您的控制器:

$scope.$on('scanner-started', function(event, args) {

    // do what you want to do
});

如果您愿意,可以在以下情况下传递参数$broadcast

$rootScope.$broadcast('scanner-started', { any: {} });

然后接收它们:

$scope.$on('scanner-started', function(event, args) {

    var anyThing = args.any;
    // do what you want to do
});

文档资料该内部范围的文档

@Ismail$scope.$apply()仅在 angular 框架之外更改模型时才需要(例如在 setTimeout、对话框回调或 ajax 回调中),换句话说,在$apply()所有代码.$on()完成后已经触发
2021-03-12 16:55:13
是否有任何推荐的做法可以将这些字符串存储在某处而不是对广播消息进行硬编码?
2021-03-16 16:55:13
您可以随意命名事件。
2021-03-26 16:55:13
@Ismail 为什么...在哪里?
2021-03-28 16:55:13
确保你是 $scope.$apply(); 你的改变!
2021-03-29 16:55:13

首先,对$on(),$broadcast()$emit()的简短描述

  • .$on(name, listener) - 通过给定的监听特定事件 name
  • .$broadcast(name, args)- 通过$scope所有孩子广播一个事件
  • .$emit(name, args)-$scope向所有父级发出一个向上层级的事件,包括$rootScope

基于以下 HTML(请参阅此处的完整示例):

<div ng-controller="Controller1">
    <button ng-click="broadcast()">Broadcast 1</button>
    <button ng-click="emit()">Emit 1</button>
</div>

<div ng-controller="Controller2">
    <button ng-click="broadcast()">Broadcast 2</button>
    <button ng-click="emit()">Emit 2</button>
    <div ng-controller="Controller3">
        <button ng-click="broadcast()">Broadcast 3</button>
        <button ng-click="emit()">Emit 3</button>
        <br>
        <button ng-click="broadcastRoot()">Broadcast Root</button>
        <button ng-click="emitRoot()">Emit Root</button>
    </div>
</div>

被触发的事件将遍历$scopes如下:

  • 广播 1 - 只会被控制器 1 看到$scope
  • Emit 1 -$scope然后会被控制器 1 看到$rootScope
  • 广播 2 - 将被控制器 2 看到,$scope然后是控制器 3$scope
  • Emit 2 -$scope然后会被控制器 2 看到$rootScope
  • 广播 3 - 只会被控制器 3 看到$scope
  • Emit 3 - 将被控制器 3 看到$scope$scope然后控制器 2$rootScope
  • 广播根-将可以看到$rootScope$scope所有的控制器(1,2,则3)
  • Emit Root - 只会被看到$rootScope

触发事件的 JavaScript(同样,您可以在这里看到一个工作示例):

app.controller('Controller1', ['$scope', '$rootScope', function($scope, $rootScope){
    $scope.broadcastAndEmit = function(){
        // This will be seen by Controller 1 $scope and all children $scopes 
        $scope.$broadcast('eventX', {data: '$scope.broadcast'});

        // Because this event is fired as an emit (goes up) on the $rootScope,
        // only the $rootScope will see it
        $rootScope.$emit('eventX', {data: '$rootScope.emit'});
    };
    $scope.emit = function(){
        // Controller 1 $scope, and all parent $scopes (including $rootScope) 
        // will see this event
        $scope.$emit('eventX', {data: '$scope.emit'});
    };

    $scope.$on('eventX', function(ev, args){
        console.log('eventX found on Controller1 $scope');
    });
    $rootScope.$on('eventX', function(ev, args){
        console.log('eventX found on $rootScope');
    });
}]);
我怎么能用你给出的例子来想象我的应用程序的层次结构。控制器如何成为父母或孩子。?我想说的是我有一系列状态,例如。LoginCtrl ->homeCrl -> notificationCtrl 等等。
2021-03-23 16:55:13

您应该知道的一件事是 $ 前缀指的是 Angular 方法, $$ 前缀指的是您应该避免使用的 Angular 方法。

下面是一个示例模板及其控制器,我们将探索 $broadcast/$on 如何帮助我们实现我们想要的。

<div ng-controller="FirstCtrl">
    <input ng-model="name"/> 
    <button ng-click="register()">Register </button>
</div>

<div ng-controller="SecondCtrl">
    Registered Name: <input ng-model="name"/> 
</div>

控制器是

app.controller('FirstCtrl', function($scope){
    $scope.register = function(){

    }
});

app.controller('SecondCtrl', function($scope){

});

我的问题是,当用户点击注册时,如何将名称传递给第二个控制器?您可能会想出多种解决方案,但我们将使用的一种是使用 $broadcast 和 $on。

$broadcast 与 $emit

我们应该使用哪个?$broadcast 将向下引导到所有子 dom 元素,而 $emit 将反向引导到所有祖先 dom 元素。

避免在 $emit 或 $broadcast 之间做出选择的最佳方法是从 $rootScope 进行通道并使用 $broadcast 到其所有子项。这使我们的案例更容易,因为我们的 dom 元素是兄弟元素。

添加 $rootScope 并让 $broadcast

app.controller('FirstCtrl', function($rootScope, $scope){
    $scope.register = function(){
        $rootScope.$broadcast('BOOM!', $scope.name)
    }
});

请注意,我们添加了 $rootScope,现在我们正在使用 $broadcast(broadcastName, arguments)。对于broadcastName,我们想给它一个唯一的名字,这样我们就可以在我们的secondCtrl 中捕捉到这个名字。我选择了BOOM!纯娱乐。第二个参数“arguments”允许我们将值传递给侦听器。

接收我们的广播

在我们的第二个控制器中,我们需要设置代码来收听我们的广播

app.controller('SecondCtrl', function($scope){
  $scope.$on('BOOM!', function(events, args){
    console.log(args);
    $scope.name = args; //now we've registered!
  })
});

真的就是这么简单。现场示例

实现类似结果的其他方法

尽量避免使用这套方法,因为它既不高效也不易于维护,但它是解决您可能遇到的问题的简单方法。

您通常可以通过使用服务或简化控制器来做同样的事情。我们不会详细讨论这个,但我想我只是为了完整性才提到它。

最后,请记住,一个非常有用的广播是“$destroy”,您可以再次看到 $ 表示它是由供应商代码创建的方法或对象。无论如何, $destroy 会在控制器被销毁时广播,您可能想听听这个以了解您的控制器何时被移除。

作为警告,尽量不要在您的应用中使用过多的广播/发射。它们可能非常难以管理,尤其是在大型应用程序中,因为追踪这些事件的根源是一项非常艰巨的任务。
2021-04-08 16:55:13
//Your broadcast in service

(function () { 
    angular.module('appModule').factory('AppService', function ($rootScope, $timeout) {

    function refreshData() {  
        $timeout(function() {         
            $rootScope.$broadcast('refreshData');
        }, 0, true);      
    }

    return {           
        RefreshData: refreshData
    };
}); }());

//Controller Implementation
 (function () {
    angular.module('appModule').controller('AppController', function ($rootScope, $scope, $timeout, AppService) {            

       //Removes Listeners before adding them 
       //This line will solve the problem for multiple broadcast call                             
       $scope.$$listeners['refreshData'] = [];

       $scope.$on('refreshData', function() {                                                    
          $scope.showData();             
       });

       $scope.onSaveDataComplete = function() { 
         AppService.RefreshData();
       };
    }); }());