我能否在 Shadow DOM 中获取一个按钮来提交不在 Shadow DOM 中的表单?

9
我刚遇到了一个有趣的情况,在一个原生自定义元素的 Shadow DOM 内部,我放置了一个提交按钮 <button>,并将其放在一个<form> 中。
  <form id="one" action="" method="get">
    <s-button>Select</s-button>
      #shadow-root
        <button>...</button>
    <button>Outside</button>
  </form>

我在<form>中有一个直接子元素<button>,这个子元素可以提交表单。但是,在影子根中的<button>却不能实现提交表单。从某种意义上讲,这是有道理的。但是,有没有人找到一种方法来告诉影子根中的<button>正确地与<form>一起使用,或者这是我必须通过JS处理的东西?我知道点击事件被阻止在Shadow DOM层,但我很惊讶居然没有办法允许按钮仍然成为表单的一部分,这可以通过属性或属性设置。当然,我可以捕获点击事件,然后从this发送一个新事件,但这并不是同样的操作,因为我的事件将不再是用户生成的,并且与此相关联有一组巨大的规则。

V2中他们正在解决更多关于shadowDOM和表单的问题。请阅读/关注:https://github.com/w3c/webcomponents/issues/187 - Danny '365CSI' Engelman
而(来自几年前的)Supersharps关于将shadowDOM输入复制到主DOM的答案:https://dev59.com/o5nga4cB1Zd3GeqPW1Lr - Danny '365CSI' Engelman
点击/提交:来自提交事件文档:“只有当用户单击表单中的提交按钮时,提交事件才会触发[...]。如果直接调用form.submit()方法,则不会引发该事件。” - Danny '365CSI' Engelman
3个回答

4

一个按钮触发提交事件(在 FORM 元素上)。

由于事件不能穿过影子 DOM 边界(不会冒泡到父级 DOM 中),所以我认为这就是为什么影子 DOM 按钮(派发 submit 事件)不会被 FORM 元素接收的原因。

需要使用 Supersharps 的解决方法,在光 DOM 中加入隐藏的按钮(然后在父 DOM 中派发 submit 事件)。

或者(从光 DOM 开始),你可以找到(父级)FORM 标签并自己派发提交事件:

this.closest('FORM').dispatchEvent(new Event('submit'))


关注影子DOM和表单领域的专家们,请前往:https://github.com/w3c/webcomponents/issues/187


customElements.define( 'my-button', class extends HTMLElement {
  connectedCallback() {
    this.attachShadow({mode:'open'}).innerHTML=`<button>Button In Shadow DOM</button>`
    this.onclick = _ => this.closest('FORM').dispatchEvent(new Event('submit'))
  }
})
<form onsubmit="return console.log('submit Event occured')">
    <my-button></my-button>
    <button>button in Document DOM</button>
</form>

嵌套的shadowDOMs

如果FORM不是直接的祖先元素,你可以通过以下方式找到它:如何在没有任何框架或库的情况下使用vanilla JS Web Components从子组件引用父组件中的方法?


2
你需要通过JavaScript来处理它。
一个简单的解决办法是在轻量级DOM中添加一个(掩码)<button>,并将click事件传递给它。最初的回答。

customElements.define( 's-button', class extends HTMLElement {
    connectedCallback() {
        this.attachShadow( {mode: 'open'})
            .innerHTML = `<button>In Shadow</button>`
        var submit = this.appendChild( document.createElement( 'button' ) )
        this.onclick = () => submit.click()
    }
} )
<form onsubmit="console.log('submitted');return false">
    <s-button>Select</s-button>
    <button>Outside</button>
</form>


0

还有一件事情,如果你的button[type=submit]已经被插入到ShadowDOM中,那么你可以做的不是完全像一个按钮。所以如果你有这样的东西:

<some-component>
<button type="submit" slot="buttonSlot"></button>
</some-component>

那个按钮可以用来触发你的表单。 该按钮位于轻量DOM中,但可以通过slot在组件内轻松处理。它还将保留所有适当的键盘、单击、焦点等事件,没有任何问题。

为了最小化轻量DOM html,甚至不需要它是type=submit,你可以在组件内设置它,并且它仍然将被视为轻量DOM中任何父级表单的提交按钮。

奖励(或者可能会产生麻烦,这取决于你的看法),它将保留页面上其他按钮的样式(除非你在组件中更改它)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接