自定义对象上的addEventListener

Hug*_*ing 56 javascript object addeventlistener cordova

我创建了一个有几种方法的对象.其中一些方法是异步的,因此我想使用事件来在方法完成时执行操作.为此,我尝试将addEventListener添加到对象.

的jsfiddle

var iSubmit = {
    addEventListener: document.addEventListener || document.attachEvent,
    dispatchEvent: document.dispatchEvent,
    fireEvent: document.fireEvent,   


    //the method below is added for completeness, but is not causing the problem.

    test: function(memo) {
        var name = "test";
        var event;
        if (document.createEvent) {
            event = document.createEvent("HTMLEvents");
            event.initEvent(name, true, true);
        } else {
            event = document.createEventObject();
            event.eventType = name;
        }
        event.eventName = name;
        event.memo = memo || { };

        if (document.createEvent) {
            try {
                document.dispatchEvent(event);
            } catch (ex) {
                iAlert.debug(ex, 'iPushError');
            }
        } else {
            document.fireEvent("on" + event.eventType, event);
        }
    }
}

iSubmit.addEventListener("test", function(e) { console.log(e); }, false);


//This call is added to have a complete test. The errors are already triggered with the line before this one.

iSubmit.test();
Run Code Online (Sandbox Code Playgroud)

这将返回错误: Failed to add eventlisterens: TypeError: 'addEventListener' called on an object that does not implement interface EventTarget."

现在这个代码将用于一个phonegap应用程序,当我这样做时,它正在使用android/ios.然而,在测试期间,如果我能够在至少一个浏览器中使用它将会很好.

PS>我知道我可以启用冒泡然后监听文档根目录,但我希望只有一点点OOP,每个对象可以独立工作.

Eva*_*You 48

addEventListener适用于实现某些与事件相关的接口的DOM元素.如果您想在纯JavaScript对象上使用事件系统,那么您正在寻找自定义事件系统.一个例子是Backbone.EventsBackbone.js.基本思想是使用对象作为哈希来跟踪已注册的回调.

我个人使用这个:https://github.com/component/emitter

这是一个相当简单和优雅的解决方案-带有般甜美短方法名on(),off()emit().您可以使用new Emitter()或使用Emitter(obj)将事件功能混合到现有对象中来创建新实例.请注意,此库是为与CommonJS模块系统一起使用而编写的,但您可以通过删除该module.exports = ...行在其他任何位置使用它.

  • 谢谢.我猜答案是"它无法完成".你的插件只不过是你已经提到过的回调系统.我宁愿重写我自己的代码来处理回调,然后使用第三方插件. (5认同)
  • 好吧,事件必须触发回调,所以如果你想调用它,事件系统本质上就是一个回调系统.EventEmitter模式在Node.js和大型前端应用程序中都非常常用,因此使用成熟的现有解决方案并不是一个坏主意. (3认同)

Pin*_*nal 15

如果你想听一个javascript对象,你有三种方法:

关于sup/pub模式:

您需要发布事件.

关于本机实现:

  • Object get/set operators足以听取添加,删除,更改,获取事件.运营商有很好的支持.仅在IE8中存在问题.但是如果你想在IE8中使用get/set Object.defineProperty但是在DOM对象上使用或者使用Object.defineProperty sham.
  • Object.prototype.watch有良好的ES5 polyfill.
  • Proxy API 需要ES Harmony支持.

Object.observe示例

var o = {};
Object.observe(o, function (changes) {
  changes.forEach(function (change) {
    // change.object contains changed object version
    console.log('property:', change.name, 'type:', change.type);
  });
});
o.x = 1     // property: x type: add
o.x = 2     // property: x type: update
delete o.x  // property: x type: delete
Run Code Online (Sandbox Code Playgroud)


Rav*_*ine 15

如果您不需要真正的事件功能(例如冒泡,stopPropagation),那么您可以实现自己的事件.addEventListener只是DOM的一个API,因此您不需要为DOM之外的对象提供它.如果你想在一个对象周围创建一个偶数模式,这是一个很好的方法,它不需要任何额外的浏览器API,并且应该是非常向后兼容的.

假设您有一个对象,您希望在调用dispatch方法时触发一系列事件:

var OurDispatcher, dispatcher;

OurDispatcher = (function() {
  function OurDispatcher() {
    this.dispatchHandlers = [];
  }

  OurDispatcher.prototype.on = function(eventName, handler) {
    switch (eventName) {
      case "dispatch":
        return this.dispatchHandlers.push(handler);
      case "somethingElse":
        return alert('write something for this event :)');
    }
  };

  OurDispatcher.prototype.dispatch = function() {
    var handler, i, len, ref;
    ref = this.dispatchHandlers;
    for (i = 0, len = ref.length; i < len; i++) {
      handler = ref[i];
      setTimeout(handler, 0);
    }
  };

  return OurDispatcher;

})();

dispatcher = new OurDispatcher();

dispatcher.on("dispatch", function() {
  return document.body.innerHTML += "DISPATCHED</br>";
});

dispatcher.on("dispatch", function() {
  return document.body.innerHTML += "DISPATCHED AGAIN</br>";
});

dispatcher.dispatch();
Run Code Online (Sandbox Code Playgroud)

在大多数情况下,它确实不必比那更复杂.通过这种方式,您可以对事件进行一些不错的控制,而不必担心向后兼容性或外部库,因为所有内容都得到了广泛支持.从技术上讲,你甚至可以不使用setTimeout并在没有任何API的情况下处理你的回调.任何其他像stopPropagation()都必须自己处理.

https://jsfiddle.net/ozsywxer/

当然,还有用于CustomEvent的polyfill,但除非我需要高级事件功能,否则我更喜欢将自己的事件系统包装到"类"中并使用它扩展其他类/函数.

这是CoffeeScript版本,它是JavaScript的衍生版本:https: //jsfiddle.net/vmkkbbxq/1/

^^有点容易理解.


tif*_*fon 10

有两个问题.

首先,该iSubmit.addEventListener()方法实际上是EventTargetDOM接口上的一个方法:

这些仅用于DOM元素.通过将它iSubmit作为方法添加到对象中,您可以在不是的对象上调用它EventTarget.这就是Chrome抛出Uncaught TypeError: Illegal invocationJavaScript错误的原因.

第一个问题是至关重要的,但是如果您可以使用EventTarget#addEventListener()您的代码将无法工作,因为事件正在添加到iSubmit但是已分派document.一般情况下,同一对象的方法需要安装事件侦听器,并分派事件(除非你使用冒泡事件,这是时要使用不同的故事 -注:冒泡并不限于JavaScript或DOM相关的事件,例如).

在自己的对象中使用自定义事件是很正常的.正如Evan Yu所说,有这样的图书馆.这是一对夫妇:

我已经习惯了js-signals并且非常喜欢它.我从未使用过Wolfy87/EventEmitter,但它看起来很漂亮.

如果您使用,您的示例可能类似于以下内容 js-signals

的jsfiddle

var iSubmit = {
    finished: new signals.Signal(),
    test: function test(memo) {
        this.finished.dispatch(memo || {});
    }
};

iSubmit.finished.add(function(data) {
    console.log('finished:', data);
});

iSubmit.test('this is the finished data');


// alternatively
iSubmit.finished.dispatch('this is dispatched directly from the signal');
Run Code Online (Sandbox Code Playgroud)


小智 8

这是一个简单的事件发射器:

class EventEmitter {
    on(name, callback) {
        var callbacks = this[name];
        if (!callbacks) this[name] = [callback];
        else callbacks.push(callback);
    }

    dispatch(name, event) {
        var callbacks = this[name];
        if (callbacks) callbacks.forEach(callback => callback(event));
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

var emitter = new EventEmitter();

emitter.on('test', event => {
    console.log(event);
});

emitter.dispatch('test', 'hello world');
Run Code Online (Sandbox Code Playgroud)


Ben*_*uer 5

如果您在 Node.js 环境中,那么您可以使用Node 的 EventEmitter 类

自定义对象.js

const EventEmitter = require('events');

class CustomObject extends EventEmitter {
  constructor() {
    super();
  }

  doSomething() {
    const event = {message: 'Hello World!'};
    this.emit('myEventName', event);
  }
}

module.exports = CustomObject;
Run Code Online (Sandbox Code Playgroud)

用法:

const CustomObject = require('./CustomObject');

// 1. Create a new instance
const myObject = new CustomObject();

// 2. Subscribe to events with ID "myEventName"
myObject.on('myEventName', function(event) {
  console.log('Received event', event);
});

// 3. Trigger the event emitter
myObject.doSomething();
Run Code Online (Sandbox Code Playgroud)

如果您想在 Node.js 环境之外使用 Node 的 EventEmitter,那么您可以使用webpack(最好是 v2.2 或更高版本)将您的捆绑包CustomClass与 EventEmitter polyfill(由 webpack 构建)一起使用。

这是它的工作原理(假设您使用 全局安装了 webpack npm install -g webpack):

  1. webpack CustomObject.js bundle.js --output-library=CustomObject
  2. 包含bundle.js在您的 HTML 页面中(它将公开window.CustomObject
  3. 没有第三步!

索引.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Title</title>
    <script src="bundle.js"></script>
  </head>
  <body>
    <script>
      // 1. Create a new instance
      const myObject = new window.CustomObject();

      // 2. Subscribe to events with ID "myEventName"
      myObject.on('myEventName', function(event) {
        console.log('Received event', event);
      });

      // 3. Trigger the event emitter
      myObject.doSomething();
    </script>
  </body>
</html>
Run Code Online (Sandbox Code Playgroud)

  • 你不知道分享这个对我有多大帮助!谢谢你! (2认同)

小智 5

只是猜测;我自己还没有尝试过。但是您可以创建一个虚拟元素,并触发/侦听该虚拟元素上的事件。另外,我更喜欢不使用库。

function myObject(){
    //create "dummy" element
    var dummy = document.createElement('dummy');
    //method for listening for events
    this.on = function(event, func){dummy.addEventListener(event, func);};
    //you need a way to fire events
    this.fireEvent = function(event, obj){
      dummy.dispatchEvent(new CustomEvent(event, {detail: obj}));
    }
}
//now you can use the methods in the object constructor
var obj = new myObject();
obj.on("custom", function(e){console.log(e.detail.result)});
obj.fireEvent("custom", {result: "hello world!!!"});
Run Code Online (Sandbox Code Playgroud)


San*_*xit 5

我已经能够通过将元素包装在 javascript 类中来实现此目的。重要的一点是元素不必存在于 dom 中。此外,元素标签名称可以是任何内容,例如自定义类名称。

'''

class MyClass
{   
    
    constructor(options ) 
    {     
    
  
        this.el =  document.createElement("MyClass");//dummy element to manage events.    
        this.el.obj= this; //So that it is accessible via event.target.obj
      
    }

    addEventListener()
    {
 
        this.el.addEventListener(arguments[0],arguments[1]);

    }
    
 

     raiseEvent()
         {
//call this function or write code below when the event needs to be raised.

            var event = new Event('dataFound');
            event.data = messageData;
            this.el.dispatchEvent(event);
        }
}


let obj = new MyClass();
obj.addEventListener('dataFound',onDataFound);

function onDataFound()
{ 
console.log('onDataFound Handler called');
}
Run Code Online (Sandbox Code Playgroud)

'''