【问题标题】:Can I get a button in Shadow DOM to submit a form not in Shadow DOM?我可以在 Shadow DOM 中获得一个按钮来提交不在 Shadow DOM 中的表单吗?
【发布时间】:2019-06-19 14:13:51
【问题描述】:

我刚刚遇到了一个有趣的情况,我在放置在 <form> 内的原生自定义元素的 Shadow DOM 内提交了 <button>

  <form id="one" action="" method="get">
    <s-button>Select</s-button>
      #shadow-root
        <button>...</button>
    <button>Outside</button>
  </form>

我还有一个&lt;button&gt; 作为&lt;form&gt; 的直系子代。

&lt;button&gt; 导致表单提交。

但 shadow-root 中的 &lt;button&gt; 没有。

在某种程度上,我想这是有道理的。但是有没有人想出一种方法来告诉 shadow-root &lt;button&gt;&lt;form&gt; 正常工作,或者这是我必须通过 JS 处理的事情?

我知道点击事件在 Shadow DOM 层被阻止,但令我惊讶的是,没有办法让按钮仍然是表单的一部分,可以通过属性或属性进行设置。

当然,我可以捕获点击事件,然后从this 发送一个新事件,但这不会做同样的事情,因为我的事件将不再是用户生成的,并且有大量与之相关的规则。

【问题讨论】:

标签: shadow-dom custom-element native-web-component


【解决方案1】:

按钮触发submit Event(在 FORM 元素上)

由于事件不能通过影子 DOM 边界(不要冒泡进入父 DOM)

我想这就是为什么 FORM 元素没有收到 shadowDOM 按钮(发送 submit 事件)的原因。

需要 Supersharps 解决方法,在 light DOM 中使用隐藏按钮(然后在父 DOM 中调度 submit 事件)

或者(从轻量级 DOM 开始)您找到(父)FORM 标签并自己发送提交事件:

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


关注 shadowDOM 和 FORM 方面的专家: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 不是直接祖先,您可以通过以下方式找到它:How to reference to a method in parent component from child component with vanilla JS Web Components? (Not any framework or Library)

【讨论】:

    【解决方案2】:

    无论如何,您都必须通过 Javascript 来处理它。

    一个简单的解决方案是在 light DOM 中添加一个(屏蔽的)&lt;button&gt;,并将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>

    【讨论】:

      【解决方案3】:

      你可以做的不是完全ShadowDOM 中的一个按钮,如果你的button[type=submit] 已经被插入到ShadowDOM 中。所以如果你有类似的东西:

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

      该按钮可用于触发您的表单。 该按钮位于 light DOM 中,但可以通过插槽在组件内轻松处理。它还将毫无问题地保留所有适当的键盘、单击、焦点等事件。

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

      奖励(或者可能会根据您的看法而带来麻烦),它将保留页面上其他按钮的样式(除非您在组件中更改它)。

      【讨论】:

        猜你喜欢
        • 2020-01-06
        • 2021-11-11
        • 1970-01-01
        • 2021-09-10
        • 2020-03-16
        • 2018-08-14
        • 2014-10-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多