customelements.define() 仅注册单个标签,真正组件库需解决命名冲突、样式隔离、属性契约、表单集成、第三方封装五大问题:命名必含短横线且全局唯一;展示型组件用 shadow dom,交互型退守 light dom;表单组件须启用 formassociated 并调用 attachinternals;attributechangedcallback 需显式声明监听属性,布尔属性值为 null 或字符串;跨组件一致性依赖约定与守卫。

customElements.define() 本身不构成组件库,它只是注册单个标签的机制。真正能称为“库”,必须解决命名冲突、样式隔离、属性契约、表单集成、第三方封装这五个硬性问题——缺一不可。
命名必须带短横线,且全局唯一
浏览器强制要求自定义元素名含短横线(如 ui-button),否则 customElements.define() 直接抛 DOMException: The element name must contain a hyphen。这不是可选项,是语法层校验。
- 命名前缀要统一,比如全部用
ui-或my-,避免混用ui-button和core-input - 重复注册会报错:
The name "ui-button" has already been used,开发时加守卫:if (!customElements.get('ui-button')) { customElements.define('ui-button', ButtonClass); } - 别用驼峰或下划线:
UiButton、ui_button全部非法;HTML 解析器只认短横线分隔
Shadow DOM 不是万能,得看组件类型
对纯展示型组件(如 ui-card、ui-badge),attachShadow({ mode: 'open' }) 是首选:样式隔离干净、结构可控、调试方便。
- 但交互强依赖外部 DOM 的组件(如
ui-chart封装 Chart.js、ui-map封装 Leaflet)不能直接用 Shadow DOM——Canvas 渲染、CSS 尺寸计算、事件委托都会失效 - 这类组件应退回到 light DOM + 命名空间 CSS 类(如
.ui-chart-wrapper),靠:host-context()或显式透传样式变量维持主题一致性 - 若坚持用 Shadow DOM,必须手动把
getComputedStyle(this)拿到的--ui-color-primary等变量注入内部元素 style,否则 CSS 变量不穿透
表单组件必须显式启用 formAssociated
写个 ui-input 却无法被 form.elements 捕获、点提交没值?大概率漏了 formAssociated: true 选项和 this.attachInternals()。
- 构造函数里必须调用
this.attachInternals(),否则this.internals.setFormValue()会报错 -
customElements.define('ui-input', InputClass, { formAssociated: true })这个选项不能省,否则attachInternals()失效 - 监听子
<input>的input事件后,必须主动调用this.internals.setFormValue(value),不能只改 DOM - 别试图继承
HTMLInputElement:Chrome v100+ 已禁用内置元素继承,Firefox/Safari 基本不支持
属性变更监听要防坑:字符串 vs 布尔,初始值 vs 更新
attributeChangedCallback 只响应 HTML 属性变更(setAttribute 或初始 HTML 写法),对 JS 属性赋值(如 el.disabled = true)完全无感。
- 必须在
static get observedAttributes()中显式声明要监听的属性,漏写就收不到回调 - 布尔属性(如
disabled、checked)的newValue是null或字符串"true",不能直接=== true判断 - 初始 HTML 中的
<ui-toggle checked></ui-toggle>会触发一次回调,但oldValue是null,别拿它做相等比较 - 想同步 JS 属性操作,得自己补逻辑:重写
set disabled(val)setter,并在里面调用this.setAttribute('disabled', '')
ui-button,而是让 ui-button、ui-input、ui-select 在同一个项目里共享颜色令牌、响应相同键盘行为、被同一套表单验证逻辑识别——这些细节没有 API 替你兜底,全靠约定和守卫。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











