Skip to content

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() 设置的是表单数据,不是组件渲染文本;表单关联回调还包括禁用、重置和表单所有者变化。能力检测必须在定义组件前完成,不能把浏览器支持情况当作业务校验结果。

练习 ​

  1. 实现 formResetCallback(),点击重置后同时清空内部输入和表单值。
  2. 用 setValidity() 让空值提交失败,并把错误消息显示给键盘和读屏用户。
  3. 写一个不支持 ElementInternals 的降级版本,比较原生输入与自定义元素的 FormData。

查看本节答案

用心记录每一步成长