简体   繁体   中英

How to work with events in pure JavaScript?

This is possibly duplicated, however, things are changing fast in JavaScript world with new browsers. I'm using some resources that used in AS3 a long time ago and now it's finally popular in JavaScript. However, I still can't make events work in my classes. I did this simple example using Mozilla MDN as guide:

var endEvent = new Event("end");

function MyClass(text){
    this.text = text;
    this.show = function(){
        console.log("MyText: "+this.text);
        this.dispatchEvent(endEvent);
    }
}

function End(evt){
    console.log("Event dispatched: "+evt);
}

function run(){
    var MyInstance = new MyClass("I have something to say...");
    MyInstance.addEventListener("end", End, false);
    MyInstance.show();
}

At the first line, Safari returns: "TypeError: '[object EventConstructor]' is not a constructor (evaluating 'new Event("end")')".

It means won't work? Is there a way to create and dispatch custom events in PURE JavaScript (won't use jQuery or anything like)?

I had this same question a bit ago

Here's the solution I came up with

requires ecmascript >= 5


function Emitter() {
  var eventTarget = document.createDocumentFragment();

  function delegate (method) {
    this[method] = eventTarget[method].bind(eventTarget);
  }

  [
    "addEventListener",
    "dispatchEvent",
    "removeEventListener"
  ].forEach(delegate, this);
}

Now a "class" that uses it

function Example() {
  Emitter.call(this);
}

Let's try it out now!

var e = new Example();

e.addEventListener("something", function(event) {
  alert("something happened! check the console too!");
  console.log(event);
});

e.dispatchEvent(new Event("something"));

Cool!


Let's see it working with your code now. Here's a demo .

// include function Emitter from above

function MyClass(text){

  Emitter.call(this);

  function show() {
    console.log("MyText:", text);
    this.dispatchEvent(new Event("end"));
  }

  this.show = show;
}

function onEnd(event){
  console.log("Event dispatched:", event);
}

function run(){
  var myInstance = new MyClass("I have something to say...");
  myInstance.addEventListener("end", onEnd, false);
  myInstance.show();
}

run();

Output

MyText: I have something to say... 
Event dispatched: Event {
  bubbles: false
  cancelBubble: false
  cancelable: false
  clipboardData: undefined
  currentTarget: null
  defaultPrevented: false
  eventPhase: 0
  path: NodeList[0]
  returnValue: true
  srcElement: null
  target: null
  timeStamp: 1406332794168
  type: "end"
  __proto__: Event
}

Lastly, here's a version of Emitter that's compatible with ecmascript < 5

// IE < 9 compatible
function Emitter() {
  var eventTarget = document.createDocumentFragment();

  function addEventListener(type, listener, useCapture, wantsUntrusted) {
    return eventTarget.addEventListener(type, listener, useCapture, wantsUntrusted);
  }

  function dispatchEvent(event) {
    return eventTarget.dispatchEvent(event);
  }

  function removeEventListener(type, listener, useCapture) {
    return eventTarget.removeEventListener(type, listener, useCapture);
  }

  this.addEventListener = addEventListener;
  this.dispatchEvent = dispatchEvent;
  this.removeEventListener = removeEventListener;
}

See document.createEvent for firing events in legacy browsers

You could make a polyfill like this (untested)

if (typeof Event !== "function") {
  function Event(type) {
    var e = document.createEvent("Event");
    e.initEvent(type, true, true);
    return e;
  }
}

Preaching for my own church here, but I happen to have worked on this very recently and wrote a tiny javascript that handles events and inheritance.

It's all on github if you want to check out some examples:

http://nicolasbize.com/moojs

(contains clickable links)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM