更改本机浏览器事件的最佳方法是什么?

时间:2018-08-28 12:19:13

标签: javascript

我正在尝试使用香草javascript临时修改事件的currentTarget属性。

我的主要目标是在事件迅速触发时快速实施,  操作完成后,请勿更改原始事件或至少将原始事件恢复为原始状态。

不幸的是,原型继承失败,并出现Illegal invocation(chrome)或'get currentTarget' called on an object that does not implement interface Event.(firefox)或The Event.currentTarget getter can only be used on instances of Event(safari)错误:

// Trigger event for demonstration 
// in a real scenario that would be caused by a user
var event = new Event('demo');
document.documentElement.addEventListener('demo', eventHandler1, false);
document.documentElement.addEventListener('demo', eventHandler2, false);
document.documentElement.addEventListener('demo', eventHandler3, false);
document.documentElement.dispatchEvent(event);

// The event handlers:
function eventHandler1(event) {
  event.currentTarget = 'MyCustomValue';
  console.log(1, event.type, event.currentTarget); // <- won't output MyCustomValue
}

function eventHandler2(event) {
  try {
    var clone = Object.create(event);
    clone.currentTarget = 'MyCustomValue';
    console.log(2, event.type, clone.currentTarget);
  } catch (e) {
    console.log(2, e.message); // <- will log an Illegal invocation error
  }
}

function eventHandler3(event) {
  var Clone = function() {
    this.currentTarget = 'MyCustomValue';
  };
  Clone.prototype = event;
  try {
    var clone = new Clone();
    console.log(3, event.type, clone.currentTarget);
  } catch (e) {
    console.log(3, e.message); // <- will log an Illegal invocation error
  }
}

对于现代浏览器,我们可以使用Proxy对象,但是我很想找到一个支持IE11的解决方案。

您是否有任何提示可以使用香草javascript实现?

1 个答案:

答案 0 :(得分:2)

概念:

第一个示例不起作用,因为您尝试使用赋值覆盖currentTarget值,因为currentTarget没有设置器,所以实际上不会覆盖该值,只有一个吸气剂。

对于第二个和第三个示例,由于您在错误的对象上调用currentTarget而抛出该错误( this将是克隆而不是原始的事件)。

要解决此问题,只需使用event而不是赋值,将新的getter或属性附加到实例Object.defineProperty上,即可将getter自身(驻留在原型中)隐藏起来:

示例:

var event = new Event('demo');
document.documentElement.addEventListener('demo', eventHandler, false);
document.documentElement.dispatchEvent(event);

function eventHandler(event) {
  Object.defineProperty(event, "currentTarget", {
    value: "MyCustomValue"
  });

  console.log(event.type, event.currentTarget);
}

还原能力:

由于新属性是分配给实例本身而不是其原型的(换句话说,新属性正在使原型中的吸气剂蒙上阴影),我们可以在之后将其删除以恢复原状。但是要做到这一点,我们必须使其可配置,否则我们将无法删除它:

Object.defineProperty(event, "currentTarget", {
  value: "MyCustomValue",
  configurable: true
});

例如,当我们要还原时,我们将其删除如下:

delete event.currentTarget;

示例:

var event = new Event('demo');
document.documentElement.addEventListener('demo', eventHandler, false);
document.documentElement.dispatchEvent(event);

function eventHandler(event) {
  console.log("Original: ", event.type, event.currentTarget);

  Object.defineProperty(event, "currentTarget", {
    value: "MyCustomValue",
    configurable: true
  });

  console.log("After overriding:", event.type, event.currentTarget);

  delete event.currentTarget;

  console.log("After reverting:", event.type, event.currentTarget);
}

注意:

您也可以使currentTarget成为吸气剂而不是属性,它也将起作用:

Object.defineProperty(event, "currentTarget", {
  get: function() { return "MyCustomValue"; },
  configurable: true
});