Передача стандартного события JavaScript со значением created=false через Shadow DOM
У меня есть настраиваемый веб-компонент с подсветкой, который содержит
<input>
элемент внутри его Shadow DOM. Я хочу отреагировать на событие, вызванное вводом за пределами настраиваемого элемента, но
change
событие по умолчанию
composed: false
, поэтому событие не проходит через границу Shadow DOM. Я мог поймать событие внутри своей реализации компонента, но
composed
свойство доступно только для чтения, поэтому я не могу обновить его и отправить тот же объект события. Я мог бы создать новый объект с помощью
new Event('change', {'composed': true})
, но тогда у него нет таких свойств, как
target
исходного события. Какой хороший подход? Следует ли мне вручную скопировать исходные свойства события в новый объект события?
1 ответ
Невозможно отправить один экземпляр более одного раза, поэтому, даже если вы можете изменить свойство исходного события, вы все равно не сможете его повторно отправить.
Таким образом, вам нужно создать новое событие для отправки из вашего настраиваемого элемента, но детали того, как именно вы хотите создать событие и что оно должно содержать, вероятно, будут зависеть от вашего варианта использования. Я бы посоветовал попытаться сделать его как можно более простым и создать мероприятие, включающее в себя необходимую информацию, а затем отправить его.
Вероятно, есть причина, по которой собственное событие изменения не
composed
, но вы можете имитировать распространение его из своего настраиваемого элемента, создав событие с именем и отправив его из своего настраиваемого элемента. В большинстве случаев вам, вероятно, даже не нужно использовать композицию, просто отправляя ее из своего настраиваемого элемента (
this
) делает его доступным в родительской области (на один уровень выше вашего теневого корня), где событие, вероятно, должно обрабатываться в большинстве случаев.
Тот факт, что у вас есть теневой корень, вероятно, следует рассматривать как деталь реализации (по крайней мере, в некоторых случаях) и не раскрывать извне без надобности, но когда вам действительно нужно раскрыть его напрямую, вы можете сделать его доступным, например, как свойство на свой настраиваемый элемент (к которому затем можно получить доступ из настраиваемого события), или вы можете включить ссылку на него в объект события (например, в свойстве CustomEvent или свойстве настраиваемого класса событий).
Например, вот как компоненты Vaadin любят
<vaadint-text-field>
распространять событие:
const changeEvent = new CustomEvent('change', {
detail: {
sourceEvent: e
},
bubbles: e.bubbles,
cancelable: e.cancelable
});
this.dispatchEvent(changeEvent);
Здесь исходное событие явно представлено как
event.detail.sourceEvent
чтобы вы могли, например, получить входное значение из своего настраиваемого события, например
event.detail.sourceEvent.target.value
.
Если вы предоставляете входной элемент через свойство (например,
myInput
) вам не нужно использовать и
detail
как тогда вы могли бы сделать что-то вроде
event.target.myInput.value
, или если исходное событие действительно вызывает
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
Вместо использования имени события вы, конечно, можете использовать свое собственное имя события, например
my-change-event
но его можно использовать, когда вы хотите, чтобы ваш пользовательский элемент вел себя как нативный, что может позволить использовать ваш компонент в качестве замены для нативного
<input>
в некоторых ситуациях (возможно, с ограничениями) или если вы просто хотите имитировать родное событие, которое уже знакомо разработчикам. В большинстве случаев, вероятно, не имеет значения,
change
событие, которое вы отправляете, создается как,
CustomEvent
или другой экземпляр, выходящий из
Event
.