Trust Event

JavaScript

在 JavaScript 中,除了用户操作触发事件外,也可以通过 Element.dispatchEvent 去触发一个事件。举例来说,对于点击事件,除了用户触发外,也可以通过下面的代码触发:

const button = document.createElement('button');
button.addEventListener('click', (event) => {
  console.log('clicked: ', event);
});
button.textContent = 'Click Me';
document.body.appendChild(button);

button.dispatchEvent(new MouseEvent('click'));

其中,点击事件更为特殊一些,还可以通过 Element 上本身自带的 .click 方法触发:

button.click();

那么,如何可以从代码层面区分,一次事件到底是用户触发的,还是程序触发的呢?

JavaScript 的 Event 中提供了一个 isTrusted 只读属性,用于标记当前的属性是否是由用户触发的。如果是,那么 isTrusted 就是 true,否则都是 false。这里无论是 dispatchEvent 还是直接调用 .click 方法,结果都是一样的(false)。

同时,因为 isTrusted 属性是只读属性,因此想要进行修改也是不会成功的:

const event = new MouseEvent('click');
console.log(event.isTrusted); // => false
event.isTrusted = true;
console.log(event.isTrusted); // => false;

而如果试图通过 Proxy 去包装 Event,最终虽然可以拿到 isTrusted=true,但是却无法被 dispatchEvent 认可:

const event = new MouseEvent('click');
const proxy = new Proxy(event, {
  get(target, prop, receiver) {
    if (prop === 'isTrusted') return true;
    return Reflect.get(target, prop);
  },
});
console.log(proxy.isTrusted); // => true
console.log(proxy instanceof MouseEvent) // => true
console.log(proxy.constructor) // => MouseEvent

// Error: Failed to execute 'dispatchEvent' on 'EventTarget':
//        parameter 1 is not of type 'Event'.
document.body.dispatchEvent(proxy);

// Success
document.body.dispatchEvent(event);