自定义元素需通过observedAttributes和attributeChangedCallback实现属性监听与同步;必须声明小写属性名数组并处理变更逻辑,手动初始化初始值、转换类型、避免保留字冲突,推荐用getter/setter同步内外状态。

自定义元素本身不提供“自定义属性接口”这个独立概念,但要让元素能响应 HTML 中声明的属性(比如 <my-input value="hello"></my-input>),必须通过标准生命周期机制实现属性监听与同步——这本质上就是你所说的“符合规范的自定义属性接口”的实现方式。
必须声明 observedAttributes 并配合 attributeChangedCallback
浏览器不会自动把 HTML 属性映射到 JS 属性或触发更新。想让元素对 value、disabled 等属性变化做出反应,需显式声明:
- 在类中定义静态 getter
observedAttributes,返回一个字符串数组,列出你要监听的属性名(全小写) - 实现
attributeChangedCallback(attrName, oldValue, newValue)方法,在其中处理值变更逻辑 - 注意:该回调不会触发初始属性值(即元素创建时已带的
value="xxx"),需在connectedCallback或constructor后手动读取并初始化
属性名必须小写,且与 HTML 中一致
HTML 属性名不区分大小写,但 DOM API 统一转为小写。比如 data-MyId、DATA-MYID 在 JS 中都会变成 data-myid:
- 声明时用小写:
static get observedAttributes() { return ['value', 'label', 'data-id']; } - 回调中接收的
attrName也始终是小写,不要写成'Value'或'VALUE' - 避免使用保留字或原生属性名冲突(如
class、id、style),它们虽可监听,但可能干扰默认行为
同步属性值到内部状态,推荐封装 setter/getter
为保持一致性,建议将属性值同步到私有字段,并通过 getter/setter 控制访问:
- 在
attributeChangedCallback中更新私有字段,例如this._value = newValue - 为
value提供公共 getter/setter:get value() { return this._value; }、set value(v) { this._value = v; this.setAttribute('value', v); } - 这样既能响应 HTML 属性变更,也能支持 JS 直接赋值:
el.value = 'new',且自动回写到 DOM 属性
避免常见陷阱:初始值、类型转换、空值处理
属性值永远是字符串,即使你在 HTML 中写 count="123" 或 active="":
- 需要手动做类型转换:
parseInt(newValue)、newValue === 'true'等 - 空字符串
""和null、undefined不同,attributeChangedCallback中oldValue为null表示首次设置,newValue为null表示属性被移除 - 布尔属性(如
disabled)通常只靠存在与否判断,可用this.hasAttribute('disabled')而非读取值


















