我刚刚遇到了一个有趣的情况,我在放置在<form>
内的本机自定义元素的 Shadow DOM 中有一个提交<button>
。
<form id="one" action="" method="get">
<s-button>Select</s-button>
#shadow-root
<button>...</button>
<button>Outside</button>
</form>
作为<form>
的直系子女,我也有<button>
.
子项<button>
导致表单提交。
但影根中的<button>
却没有。
在某种程度上,我想这是有道理的。但是有没有人想出一种方法来告诉影根<button>
与<form>
正常工作,或者这是我必须通过 JS 处理的事情吗?
我知道点击事件在 Shadow DOM 层被阻止,但我很惊讶没有办法让按钮仍然是表单的一部分,这可以通过属性或属性进行设置。
当然,我可以捕获点击事件,然后从this
发送一个新事件,但这不会做同样的事情,因为我的事件将不再是用户生成的,并且有大量与此相关的规则。
触发提交事件(在 FORM 元素上)
由于事件不能通过影子 DOM 边界(不要冒泡到父 DOM 中)
我认为这就是为什么 FORM 元素没有收到 shadowDOM 按钮(调度submit
事件)的原因。
需要 Supersharps 解决方法,在轻型 DOM 中使用隐藏按钮(然后在父 DOM 中调度submit
事件)
或者(从轻 DOM 开始)您找到(父)FORM 标签并自己调度提交事件:
this.closest('FORM').dispatchEvent(new Event('submit'))
关注shadowDOM和FORMS的专家: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>
嵌套的影子 DOM
如果 FORM 不是直接祖先,你可以这样找到它:如何使用原版 JS Web 组件从子组件引用父组件中的方法?(不是任何框架或库)
,你都必须通过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>
你可以做的其他事情不完全是ShadowDOM中的按钮,如果你的button[type=submit]
已入ShadowDOM中。因此,如果您有类似以下内容:
<some-component>
<button type="submit" slot="buttonSlot"></button>
</some-component>
该按钮可用于触发表单。该按钮位于轻型 DOM 中,但可以通过插槽从组件内部轻松处理。它还将保留所有适当的键盘,单击,焦点等事件,而不会遇到任何麻烦。
为了最小化轻量级 DOM html,您甚至不需要它成为type=submit
您可以从组件中设置它,它仍将被视为轻量级 DOM 中任何父表单的提交按钮。
奖励(或者可能麻烦,取决于您如何看待它),它将保留页面上其他按钮的样式(除非您在组件中更改它)。