问题描述
我有一个自定义的 lit web 组件,它的 Shadow DOM 中包含一个 <input>
元素。我想对自定义元素外部的输入触发的 change
事件做出反应,但 change
事件默认具有 composed: false
,因此该事件不会通过 Shadow DOM 边界.我可以在组件实现中捕获事件,但 composed
属性是只读的,因此我无法更新它并分派相同的事件对象。我可以使用 new Event('change',{'composed': true})
创建一个新对象,但是它没有原始事件的 target
之类的属性。什么是好的方法?我应该手动将原始事件的属性复制到新的事件对象吗?
解决方法
不可能多次调度单个 Event
实例,因此即使您可以修改原始事件的 composed
属性,您也无法重新调度它。
因此,您需要创建一个新事件以从您的自定义元素调度,但是您希望如何创建事件以及它应该包含什么的详细信息可能取决于您的用例。我建议尽量保持简单,并制作一个包含您需要的信息的事件,然后发送它。
原生 change 事件不是 composed
可能是有原因的,但是您可以通过创建一个名为 change
的事件并分派它来模拟将其传播出您的自定义元素从您的自定义元素。在大多数情况下,您甚至可能不需要使用 composed,因为只需从您的自定义元素 (this
) 分派它就可以在父作用域(从您的影子根上一层)中使用它大多数情况下可能应该处理事件的位置。
您的 shadow root 中有 <input>
的事实可能应该被视为一个实现细节(至少在某些情况下)而不是不必要地暴露在外面,但是当您确实需要直接公开它时,您可以使它可用,例如作为您的自定义元素的属性(然后可以从您的自定义事件访问),或者您可以在事件对象中包含对它的引用(例如,在 CustomEvent 的 detail
属性或自定义事件类)。
例如 here's 像 <vaadint-text-field>
这样的 Vaadin 组件如何传播 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
)公开输入元素,则不需要使用 CustomEvent
和 detail
,因为您可以执行类似 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>
的替代品,或者如果您只想模仿原生 {{1}开发人员已经熟悉的事件。在大多数情况下,您调度的 change
事件是否创建为 change
、Event
或其他从 CustomEvent
扩展的实例可能无关紧要。