ElementInternals 与表单值
Form-associated custom element 可以像原生输入控件一样参加表单提交和约束校验。关键是声明 formAssociated,并通过 attachInternals() 设置表单值;仅改变组件内部文本不会自动进入 FormData。
最小实验:自定义控件参与提交
html
<form id="profile"><profile-name name="displayName"></profile-name><button>提交</button></form>
<pre id="log"></pre>
<script>
class ProfileName extends HTMLElement {
static formAssociated = true
constructor() {
super()
this._internals = this.attachInternals()
this.input = document.createElement('input')
this.input.addEventListener('input', () => this._internals.setFormValue(this.input.value))
this.append(this.input)
}
}
customElements.define('profile-name', ProfileName)
document.querySelector('#profile').addEventListener('formdata', (event) => {
document.querySelector('#log').textContent = JSON.stringify([...event.formData.entries()])
})
</script>输入 Ada 后提交,预期日志包含 displayName=Ada。在不支持 ElementInternals 的浏览器中观察构造函数失败,并为控件提供原生 <input> 降级。
机制与边界
setFormValue() 设置的是表单数据,不是组件渲染文本;表单关联回调还包括禁用、重置和表单所有者变化。能力检测必须在定义组件前完成,不能把浏览器支持情况当作业务校验结果。
练习
- 实现
formResetCallback(),点击重置后同时清空内部输入和表单值。 - 用
setValidity()让空值提交失败,并把错误消息显示给键盘和读屏用户。 - 写一个不支持
ElementInternals的降级版本,比较原生输入与自定义元素的FormData。