通过影子DOM传递composited=false的标准JavaScript事件

通过影子DOM传递composited=false的标准JavaScript事件,javascript,shadow-dom,lit-element,lit,Javascript,Shadow Dom,Lit Element,Lit,我有一个自定义的Light web组件,它在阴影DOM中包含一个元素。我想对自定义元素之外的输入触发的change事件做出反应,但是change事件默认情况下具有组合的false,因此事件不会通过阴影DOM边界。我可以在我的组件实现中捕获事件,但是composited属性是只读的,所以我不能更新它并分派相同的事件对象。我可以用newevent('change',{'composited':true})创建一个新对象,但是它没有原始事件的target这样的属性。什么是好方法?我是否应该手动将原始事

我有一个自定义的Light web组件,它在阴影DOM中包含一个
元素。我想对自定义元素之外的输入触发的
change
事件做出反应,但是
change
事件默认情况下具有组合的
false
,因此事件不会通过阴影DOM边界。我可以在我的组件实现中捕获事件,但是
composited
属性是只读的,所以我不能更新它并分派相同的事件对象。我可以用
newevent('change',{'composited':true})
创建一个新对象,但是它没有原始事件的
target
这样的属性。什么是好方法?我是否应该手动将原始事件的属性复制到新的事件对象?

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

因此,您需要创建一个新的事件来从自定义元素中分派,但是您希望如何创建事件以及事件应该包含什么的详细信息可能取决于您的用例。我建议尽量保持简单,制作一个包含您所需信息的活动,然后发送

本机事件不是由
组成的
,这可能是有原因的,但是您可以通过创建一个名为
change
的事件并从自定义元素中分派它来模拟将其传播出自定义元素。在大多数情况下,您甚至可能不需要使用它,因为只要从自定义元素(
this
)分派它,它就可以在父范围(从阴影根向上一级)中使用,在大多数情况下,可能应该在父范围中处理事件

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

例如,Vaadin组件如
如何传播
更改事件:

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
事件实际上导致自定义元素上的
属性发生更改,您可以改为读取该属性

// 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

当然,您可以使用自己的自定义事件名称,如
my change event
,而不是使用事件名称
change
,但是当您希望自定义元素的行为类似于本机
时,可以使用
change
,这样可以将您的组件用作本机组件的插入式替换
在某些情况下(可能有限制),或者如果您只是想模拟开发人员已经熟悉的本机
更改
事件。在大多数情况下,您分派的
更改
事件是否创建为
事件
自定义事件
或从
事件
扩展的其他实例可能无关紧要,但目标可能是影子DOM内部的输入,并且不应从外部“知道”。。。你确定要这样吗?我认为目标应该是组件而不是输入。至少这是一个良好的开端。我到底是应该触发一个“更改”事件,还是应该触发一些
CustomEvent
?我想知道,从API的角度来看,这是否有意义?组件的用户是否会期望“更改”事件?在customevent或change事件之间进行选择是合理的,而且可能两者都可以。我会去参加一个变革活动,如果你在变革发生时启动它。(您发送的数据是否适合更改事件?)。但是,向目标发送组件内部的、对组件用户隐藏的内容是毫无疑问的。(至少对我来说)
// 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