我可以在 Shadow DOM 中获得一个按钮来提交不在 Shadow DOM 中的表单吗?
Posted
技术标签:
【中文标题】我可以在 Shadow DOM 中获得一个按钮来提交不在 Shadow DOM 中的表单吗?【英文标题】:Can I get a button in Shadow DOM to submit a form not in 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>
我还有一个<button>
作为<form>
的直系子代。
子 <button>
导致表单提交。
但 shadow-root 中的 <button>
没有。
在某种程度上,我想这是有道理的。但是有没有人想出一种方法来告诉 shadow-root <button>
与 <form>
正常工作,或者这是我必须通过 JS 处理的事情?
我知道点击事件在 Shadow DOM 层被阻止,但令我惊讶的是,没有办法让按钮仍然是表单的一部分,可以通过属性或属性进行设置。
当然,我可以捕获点击事件,然后从this
发送一个新事件,但这不会做同样的事情,因为我的事件将不再是用户生成的,并且有大量与之相关的规则。
【问题讨论】:
他们在 V2 中处理的 shadowDOM 和表单存在更多问题。请阅读/关注:github.com/w3c/webcomponents/issues/187 并且(从几年前开始)Supersharps 对将 shadowDOM 输入复制到主 DOM 的回答:***.com/questions/38623176/… 点击/提交时:来自the submit Event documentation:“提交事件仅在用户单击表单中的提交按钮[..]时触发。调用form.submit时不会引发该事件() 方法直接。" 【参考方案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 中添加一个(屏蔽的)<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>
【讨论】:
【参考方案3】:你可以做的不是完全ShadowDOM 中的一个按钮,如果你的button[type=submit]
已经被插入到ShadowDOM 中。所以如果你有类似的东西:
<some-component>
<button type="submit" slot="buttonSlot"></button>
</some-component>
该按钮可用于触发您的表单。 该按钮位于 light DOM 中,但可以通过插槽在组件内轻松处理。它还将毫无问题地保留所有适当的键盘、单击、焦点等事件。
要最小化轻量级 DOM html,您甚至不需要将其设置为 type=submit
,您可以在组件中设置它,它仍将被视为轻量级 DOM 中任何父表单的提交按钮。
奖励(或者可能会根据您的看法而带来麻烦),它将保留页面上其他按钮的样式(除非您在组件中更改它)。
【讨论】:
以上是关于我可以在 Shadow DOM 中获得一个按钮来提交不在 Shadow DOM 中的表单吗?的主要内容,如果未能解决你的问题,请参考以下文章