Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angularjs/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何在服务中封装单个事件和临时事件?_Javascript_Angularjs_Angularjs Scope_Dom Events - Fatal编程技术网

Javascript 如何在服务中封装单个事件和临时事件?

Javascript 如何在服务中封装单个事件和临时事件?,javascript,angularjs,angularjs-scope,dom-events,Javascript,Angularjs,Angularjs Scope,Dom Events,我试图将事件封装在服务中,以便在控制器的作用域被破坏时实现订阅/取消订阅侦听器的机制。这是因为我一直以以下方式使用rootScope.$on: if(!$rootScope.$$listeners['event']) { $rootScope.$on('event', function(ev, data){ // do some... }); } 或 所以我只需要这个事件的一个监听器,我需要在控制器不再处于活动状态时删除现有的监听器,因为我之前注册的函数仍在被触

我试图将事件封装在服务中,以便在控制器的作用域被破坏时实现订阅/取消订阅侦听器的机制。这是因为我一直以以下方式使用
rootScope.$on

if(!$rootScope.$$listeners['event']) {
    $rootScope.$on('event', function(ev, data){
        // do some...
    });
}

所以我只需要这个事件的一个监听器,我需要在控制器不再处于活动状态时删除现有的监听器,因为我之前注册的函数仍在被触发

因此,我需要在我的控制器上实现一个
$destroy
事件侦听器,以便在范围被销毁时销毁侦听器,但我不希望每次创建事件时都执行该代码。 这就是为什么我想创建一个服务,在其中我将封装事件

angular.module('core').factory('event', [
    function() {
        var service = {};
        service.events = {};
        service.on = function(scope, eventId, callback) {
            scope.$on('$destroy', function(ev, other){
                //unsubscribe
            });
            service.events[eventId] = callback;
            // scope = null; I guess ?
        };
        service.emit = function(eventId, data){
            if (service.events[eventId])
                service.events[eventId](data);
            else
                return new Error('The event is not subscribed');
        };
        return service;
    }
]);
这可以使用$rootScope而不是我自己的方法来完成,但要封装$rootScope
$on
$emit
,但最后我会遇到同样的问题

以下是我的问题:

  • 将范围引用值传递给服务是一种好的做法吗
  • $$destromed
    的含义是什么?如果这是真的,意味着angularJS没有对实例的内部引用
  • 我应该在我的服务中执行作用域=null以允许GC删除对象,还是angularJS处理显式删除
  • 有没有更好的方法来做我想做的事

  • 您试图完成的基本上是一个事件总线
    您还很好地描述了当前实现的错误。 解决这个问题的另一种方法是用您的总线(或任何其他事件总线)装饰$rootScope。以下是如何:

    app.config(function ($provide) {
    $provide.decorator('$rootScope', ['$delegate', '$$bus', function ($delegate, $$bus) {
      Object.defineProperty($delegate.constructor.prototype, '$bus', {
        get: function () {
          var self = this;
    
          return {
            subscribe: function () {
              var sub = $$bus.subscribe.apply($$bus, arguments);
    
              self.$on('$destroy',
                function () {
                  console.log("unsubscribe!");
                  sub.unsubscribe();
    
                });
            },
    
            publish: $$bus.publish
          };
        },
        enumerable: false
      });
    
      return $delegate;
    }]);
    });
    
    考虑以下$$总线实现(为了简单起见保持基本):

    现在您所要做的就是订阅或发布事件。取消订阅将自动进行(当$scope被销毁时):

    然后发布一个事件:

      $scope.$bus.publish('test', {name: "publishing event!"});
    
    重要的一点是,事件本身订阅到每个单独的$scope,而不是$rootScope。这就是您“知道”要发布哪个$scope的方式

    我想这回答了你的问题。考虑到这一点,您显然可以使该机制更加复杂(例如,当视图路由时释放控制器事件侦听器,仅自动取消订阅某些事件,等等)。 祝你好运


    **此解决方案采用了使用不同总线框架的形式(除此之外是相同的)。

    我在所有项目中使用的“!!!”@dandavis==”是什么意思,所以我正在使用!!为了铸造虚假的价值观,我又一次匆忙地否定了。。我知道。。只是好的,谢谢!这正是我需要的,这个解决方案非常完美。
    app.factory('$$bus', function () {
      var api = {};
      var events = {};
    
      api.subscribe = function (event) {
        if (!events.hasOwnProperty(event.name)) {
          events[event.name] = [event];
        } else {
          events[event.name].push(event);
        }
        return {
          unsubscribe: function () {
            api.unsubscribe(event);
          }
        }
      };
    
      api.publish = function (eventName, data) {
        if (events.hasOwnProperty(eventName)) {
          console.log(eventName);
    
          angular.forEach(events[eventName], function (subscriber) {
            subscriber.callback.call(this, data);
          });
        }
      };
    
      api.unsubscribe = function (event) {
        if (events.hasOwnProperty(event.name)) {
          events[event.name].splice(events[event.name].indexOf(event), 1);
          if (events[event.name].length == 0) {
            delete events[event.name];
          }
        }
      };
    
      return api;
    });
    
      $scope.$bus.subscribe({
        name: 'test', callback: function (data) {
          console.log(data);
        }
      });
    
      $scope.$bus.publish('test', {name: "publishing event!"});