自定义元素需通过get/set访问器实现.value属性读写并同步DOM,监听子元素input/change事件触发对应事件,响应外部赋值更新UI,且通过formAssociated接口集成表单提交与验证。

自定义元素要实现类似原生 <input> 的取值逻辑,核心是让外部能通过 .value 属性读写,并在用户交互时自动同步、触发 input 和 change 事件。这不单是加个 value 属性那么简单,得模拟原生行为的一致性。
暴露可读写的 value 属性
用 get/set 访问器控制内部状态,同时保持与 DOM 属性的同步:
- 在
set value()中更新内部状态(如this._value),并同步到实际渲染的子元素(比如内部的<input>或<textarea>) - 在
get value()中返回当前值,优先返回内部状态,避免直接读取子元素值(防止绕过 setter 逻辑) - 初始化时从
this.getAttribute('value')读取初始值,确保支持 HTML 属性赋值
监听输入并触发标准事件
内部子元素(如 <input type="text">)需绑定 input 和 change 事件:
-
input事件中调用this.value = e.target.value,触发 setter 并更新内部状态 - 紧接着用
this.dispatchEvent(new Event('input', { bubbles: true }))向外冒泡,和原生一致 -
change事件同样转发,注意只在失去焦点且值真正改变时触发(可参考原生逻辑:比较oldValue !== newValue)
响应外部 value 赋值并更新 UI
当 JS 代码执行 myInput.value = 'xxx' 时,不仅要改内部状态,还得反映到界面:
- 在
set value()中,同步设置内部子元素的.value(或.textContent,取决于类型) - 如果子元素是
<input>,还要处理光标位置、选区等细节(可选),否则批量赋值后焦点可能错乱 - 对
disabled、readonly等属性也应响应,例如设为disabled时禁用内部控件
兼容表单提交与 FormData
若希望被包含在 <form> 中并参与序列化,需实现 formAssociated:
- 定义
static formAssociated = true - 在构造函数中调用
this.attachInternals(),获取internals实例 - 通过
this.internals.setFormValue(this.value)告诉表单当前值 - 重写
reportValidity()和checkValidity()来支持验证逻辑


















