Как добавитьEventListener к элементам не DOM в JavaScript? - PullRequest
7 голосов
/ 03 июня 2011

В Java, C #, Actionscript и т. Д. События предназначены для классов, тогда как в Javascript он кажется ограниченным dom.Я читаю здесь пример того, как сделать это с помощью jquery http://www.west -wind.com / weblog / posts / 2010 / May / 27 / NonDom-Element-Event-Binding-with-jQuery

но если мне не нужен jquery и если я хочу понять механизм, как бы вы это сделали?

Ответы [ 2 ]

4 голосов
/ 08 октября 2014

Для этого есть как минимум два способа:

- если вы являетесь пользователем JQuery (в настоящее время я не являюсь), вы можете заключить свой простой объект JavaScript в JQuery, а затем в элементы DOM, он может слушать события.Этот метод уже имеет ответ здесь .Я не уверен, как этот метод работает под капотом, я планирую исследовать позже, и вы можете исследовать самостоятельно.

- С VanillaJS вы можете добиться того же эффекта, создав насыщенный «класс»из которого будут получены / созданы все объекты, которые хотят взаимодействовать.Тогда все экземпляры этого класса смогут регистрировать, излучать и транслировать событие.Заимствуя семантику из DOM API и AngularJS, я написал пример, который демонстрирует, как это можно сделать и как это можно использовать.Вот оно:

/**
 * EventfulObject constructor/base.
 * @type EventfulObject_L7.EventfulObjectConstructor|Function
 */
var EventfulObject = function() {
  /**
   * Map from event name to a list of subscribers.
   * @type Object
   */
  var event = {};
  /**
   * List of all instances of the EventfulObject type.
   * @type Array
   */
  var instances = [];
  /**
   * @returns {EventfulObject_L1.EventfulObjectConstructor} An `EventfulObject`.
   */
  var EventfulObjectConstructor = function() {
    instances.push(this);
  };
  EventfulObjectConstructor.prototype = {
    /**
     * Broadcasts an event of the given name.
     * All instances that wish to receive a broadcast must implement the `receiveBroadcast` method, the event that is being broadcast will be passed to the implementation.
     * @param {String} name Event name.
     * @returns {undefined}
     */
    broadcast: function(name) {
      instances.forEach(function(instance) {
        (instance.hasOwnProperty("receiveBroadcast") && typeof instance["receiveBroadcast"] === "function") &&
        instance["receiveBroadcast"](name);
      });
    },
    /**
     * Emits an event of the given name only to instances that are subscribed to it.
     * @param {String} name Event name.
     * @returns {undefined}
     */
    emit: function(name) {
      event.hasOwnProperty(name) && event[name].forEach(function(subscription) {
        subscription.process.call(subscription.context);
      });
    },
    /**
     * Registers the given action as a listener to the named event.
     * This method will first create an event identified by the given name if one does not exist already.
     * @param {String} name Event name.
     * @param {Function} action Listener.
     * @returns {Function} A deregistration function for this listener.
     */
    on: function(name, action) {
      event.hasOwnProperty(name) || (event[name] = []);
      event[name].push({
        context: this,
        process: action
      });

      var subscriptionIndex = event[name].length - 1;

      return function() {
        event[name].splice(subscriptionIndex, 1);
      };
    }
  };

  return EventfulObjectConstructor;
}();

var Model = function(id) {
  EventfulObject.call(this);
  this.id = id;
  this.receiveBroadcast = function(name) {
    console.log("I smell another " + name + "; and I'm model " + this.id);
  };
};
Model.prototype = Object.create(EventfulObject.prototype);
Model.prototype.constructor = Model;

// ---------- TEST AND USAGE (hopefully it's clear enough...)
// ---------- note: I'm not testing event deregistration.

var ob1 = new EventfulObject();
ob1.on("crap", function() {
  console.log("Speaking about craps on a broadcast? - Count me out!");
});

var model1 = new Model(1);

var model2 = new Model(2);
model2.on("bust", function() {
  console.log("I'm model2 and I'm busting!");
});

var ob2 = new EventfulObject();
ob2.on("bust", function() {
  console.log("I'm ob2 - busted!!!");
});
ob2.receiveBroadcast = function() {
  console.log("If it zips, I'll catch it. - That's me ob2.");
};

console.log("start:BROADCAST\n---------------");
model1.broadcast("crap");
console.log("end  :BROADCAST\n---------------\n-\n-\n");
console.log("start:EMIT\n---------------");
ob1.emit("bust");
console.log("end:EMIT\n---------------");
<h1>THE CODE IS IN the JavaScript pane!</h1>
<h3>AND... THE SHOW IS ON YOUR CONSOLE!</h3>

Вы можете использовать это в качестве основы для более надежного решения.

3 голосов
/ 20 сентября 2013

в самом простом случае механизм выглядит примерно так:

function PubSub() {
    this.subs = {};
    this.subscribe = function(channel, sub) {
        this.subs[channel] = this.subs[channel] || []; //create array for channel
        this.subs[channel].push(sub);
    };
    this.publish = function(channel) {
        var args = [].slice.call(arguments, 1); //pop off channel argument
        this.subs[channel].forEach(function(sub) {
            sub.apply(void 0, args); //call each method listening on the channel
        });
    };
}

демо здесь: http://jsfiddle.net/3PNtR/

- РЕДАКТИРОВАТЬ (~ 5 лет спустя) -

тот же простой механизм, новый синтаксис

class PubSub {
    constructor () {
        this.subs = {}
    }
    subscribe (channel, sub) {
        this.subs[channel] = this.subs[channel] || []
        this.subs[channel].push(sub)
    }
    publish (channel, ...args) {
        ;(this.subs[channel] || []).forEach(sub => sub(...args))
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...