如何设置Event的EventTarget

时间:2016-05-26 09:12:31

标签: javascript

如何设置活动的EventTarget

var myObj = {foo: 'bar'};
var event = new Event('eventName');
event.target = myObj;

将导致以下错误:

Uncaught TypeError: Cannot set property target of #<Event> which has only a getter

修改

我想写这样的东西,我的班级将是target

class MyClass {

  constructor() {
    this.listeners = {};
  }

  addEventListener(type, callback) {
    if (!(type in this.listeners)) {
      this.listeners[type] = [];
    }
    this.listeners[type].push(callback);
  }

  removeEventListener() {
    if (!(type in this.listeners)) {
      return;
    }
    var stack = this.listeners[type];
    for (var i = 0, l = stack.length; i < l; i++) {
      if (stack[i] === callback) {
        stack.splice(i, 1);
        return this.removeEventListener(type, callback);
      }
    }
  }

  dispatchEvent(event) {
    if (!(event.type in this.listeners)) {
      return;
    }
    var stack = this.listeners[event.type];
    event.target = this;
    for (var i = 0, l = stack.length; i < l; i++) {
      stack[i].call(this, event);
    }
  }

}

let myInstance = new MyClass();
let event = new Event('eventName');
myInstance.dispatchEvent();

更多信息:https://developer.mozilla.org/en/docs/Web/API/EventTarget

3 个答案:

答案 0 :(得分:12)

好的 - 我只是有一个脑波,所以这里的另一个答案对你来说非常顽皮,可能只是工作。 (为我工作;)

您可以尝试:{/ p>而不是const object1 = {}; Object.defineProperty(object1, 'property1', { value: [{ value: 42, writable: false }] }); console.log(object1.property1[0].value); console.log(object1.property1[0].writable);

event.target = myObj

我可能在这里错了,但我认为新的Object.defineProperty(event, 'target', {writable: false, value: myObj}); 属性会隐藏原始属性。它与浏览器内部事件调度的工作方式不同,浏览器事件处理代码几乎肯定会忽略它,但它可能足以欺骗依赖target的javascript代码。

另外,请注意在不同的浏览器中测试它,因为某些浏览器可能会将Event.target定义为不可配置的属性。

答案 1 :(得分:4)

关于您的修改, 显着 会更改问题。现在的答案是:不要使用CustomEvent,您尝试将其用于非预期目的。只需使用您自己的对象,因为您从不将事件分派给DOM元素。

发送事件时自动设置:

targetElement.dispatchEvent(event);

如果要包含除事件的元素以外的自定义数据,只需将其添加为属性:

event.data = myObj;

示例:

&#13;
&#13;
"use strict";
var div = document.getElementById("target");

div.addEventListener(
  "eventName",
  function(e) {
    console.log("e.target:", e.target);
    console.log("e.data:", e.data);
  },
  false
);

var myObj = {foo: "bar"};
var event = new Event("eventName");
event.data = myObj;
div.dispatchEvent(event);
&#13;
<div id="target"></div>
&#13;
&#13;
&#13;

答案 2 :(得分:1)

从你原来的问题起1年,9个月了,我想用完全相同的代码从完全相同的地方做到这一点。我确切地知道你为什么要这样做,这是因为EventTarget在所有浏览器中都不是可构造的对象。似乎没有,你的问题没有真正的解决方案。

如果其他人遇到此问题并在此页面上遇到麻烦,解决方案就是不依赖Event.target。您可以创建自定义事件并按如下方式调度:

var myeventtarget = new MyClass();

var ev = new CustomEvent('myevent', {
    detail: {
        target: myeventtarget
    }});

myeventtarget.dispatchEvent(ev);

然后,在事件处理程序中,可以使用以下命令访问目标:

var event_handler = function(ev) {
    var target = ev.detail.target;
    alert(target);
}

这是一种真正丑陋的语法,但它看起来像是现在唯一可以实现的“正确”方式。现在,如果您忽略旧浏览器,我知道在较新的Firefox和Chrome浏览器中,您可以像这样实现MyClass

class MyClass extends EventTarget {
    constructor() {
        super()
    }
}

在给定上述定义的情况下,我没有测试在MyClass类型的对象上调度时是否设置了事件目标,但如果没有,则可能值得将其作为对DOM Living Standard的更改这显然是有道理的。 (规范目前似乎并不表明它应该有用)

最后,我是否可以提醒您不要使用您正在使用的javascript EventTarget代码而不检查它是否正常工作。我发现当你把它EventListener一个对象时,它会中断。如果您将同一事件两次交给addEventListener(),它也会附加一个重复事件,而DOM Living Standard明确指出它不能这样做。幸运的是,很容易解决这些问题。您需要将stack[i].call(this, event);更改为:

if (stack[i].handleEvent) stack[i].handleEvent(event);
        else stack[i].call(this, event);

并添加以下内容:

var stack = this.listeners[type];
for (var i = 0, l = stack.length; i < l; i++) {
    if (stack[i] === callback){
        return;
    }
}

之前this.listeners[type].push(callback);

其他问题是addEventListener()如果你把它变成一个空回调(另一个简单的修复)就不会简单地返回,显然它不允许将选项交给它。 (但决定你是否真的需要这个功能)