3

<input>我有一个自定义的发光 Web 组件,它在其 Shadow DOM中包含一个元素。我想对change自定义元素外部的输入触发的事件做出反应,但该change事件默认具有composed: false,因此该事件不会通过 Shadow DOM 边界。我可以在组件实现中捕获该事件,但该composed属性是只读的,因此我无法更新它并调度相同的事件对象。我可以用 来创建一个新对象 new Event('change', {'composed': true}),但是它没有target原始事件的属性。什么是好方法?我应该手动将原始事件的属性复制到新的事件对象吗?

4

1 回答 1

2

不可能Event多次分派单个实例,因此即使您可以修改composed原始事件的属性,也无法重新分派它。

因此,您需要创建一个新事件以从您的自定义元素中调度,但是您希望如何准确地创建事件以及它应该包含什么的细节可能取决于您的用例。我建议尽量让它尽可能简单,并制作一个包含您需要的信息的事件,然后发送它。

原生更改事件不是可能是有原因的composed,但您可以通过创建具有名称的事件change并从自定义元素调度它来模拟从自定义元素传播它。在大多数情况下,您甚至可能不需要使用组合this,因为只需从您的自定义元素 ( ) 分派它就可以在父范围(从您的影子根向上一级)中使用它,这可能是大多数情况下应该处理的事件案例。

您的影子根中有一个事实<input>可能应该被视为实现细节(至少在某些情况下)并且不会不必要地暴露在外部,但是当您确实需要直接暴露它时,您可以使其可用,例如作为属性在您的自定义元素上(然后可以从您的自定义事件中访问),或者您可以在事件对象中包含对它的引用(例如,在CustomEventdetail的属性或自定义事件类的属性中)。

例如,这是Vaadin 组件<vaadint-text-field>传播change事件的方式:

const changeEvent = new CustomEvent('change', {
  detail: {
    sourceEvent: e
  },
  bubbles: e.bubbles,
  cancelable: e.cancelable
});
this.dispatchEvent(changeEvent);

在这里,原始事件被显式公开event.detail.sourceEvent,例如,您可以从自定义change事件中获取输入值,例如event.detail.sourceEvent.target.value.

如果您通过myInput不需要使用的属性(例如 )公开输入元素CustomEventdetail那么您可以执行类似的操作event.target.myInput.value,或者如果原始change事件实际上导致value自定义元素上的属性发生更改,则您可以改为阅读它。

// Dispatch event (in your custom element)
const changeEvent = new Event('change', {
  bubbles: e.bubbles,
  cancelable: e.cancelable
});
this.dispatchEvent(changeEvent);

// Read the input value in event handler (assuming your custom element
// has declared `myInput` as a reference to the `<input>`)
event.target.myInput.value
// Alternatively access via shadowRoot (not very nice)
event.target.shadowRoot.querySelector('input').value

如果您创建这样的自定义事件类,您还可以在事件中包含自定义属性或方法:

// Declare event class once somewhere
class MyChangeEvent extends Event {
  constructor(sourceEvent) {
    super('change', {
      bubbles: sourceEvent.bubbles,
      cancelable: sourceEvent.cancelable,
    });
    this.sourceEvent = sourceEvent;
  }
}

// Trigger a custom event
this.dispatchEvent(new MyChangeEvent(e));

// Access custom event property in an event handler
event.sourceEvent

除了使用事件名称之外change,您当然可以使用自己的自定义事件名称,my-change-event但是change当您希望自定义元素表现得像本机时应该可以使用,<input>这可能允许您的组件用作替代在某些情况下是原生<input>的(可能有限制),或者如果你只是想模仿change开发人员已经熟悉的原生事件。change在大多数情况下,您分派的事件是创建为EventCustomEvent还是从 扩展的其他实例可能并不重要Event

于 2021-06-08T06:29:19.987 回答