核心是守住命名规范、属性契约、shadow dom封装策略三道防线;自定义元素名必须含短横线且全项目统一前缀,attributechangedcallback仅响应显式声明的属性,shadow dom不继承:root变量,connectedcallback只触发一次,接口文档约束比组件数量更重要。

直接说结论:用 HTML 自定义元素构建一致性 UI 系统,核心不是写多少组件,而是守住三道防线——命名规范、属性契约、Shadow DOM 封装策略;漏掉任何一条,ds-button 和 ui-button 就会变成两个不兼容的实现。
自定义元素名必须含短横线,且全项目统一前缀
浏览器强制要求自定义标签名包含短横线(-),这是硬性语法限制。但更关键的是前缀一致性:ds-、ui-、core- 必须在整个系统中固定使用一个,不能混用。
-
ds-button和ui-button在 DOM 中是完全不同的构造函数实例,无法共享样式、事件或类型检查 - 前缀泄露设计归属:比如
ds-暗示 Design System,app-暗示业务层封装,混用会让团队失去语义锚点 - 构建工具(如 Vite)对未注册标签不做警告,
<ui-button></ui-button>写错成<ds-button></ds-button>时,页面只渲染为HTMLUnknownElement,控制台无报错,排查成本高
attributeChangedCallback 不等于“监听所有属性变化”
attributeChangedCallback 只响应你明确列在 static get observedAttributes() 里的属性,并且只对 setAttribute() 或初始 HTML 属性生效。它不是 Vue 的 watch,也不是 React 的 useEffect。
- 写
<ds-input value="abc"></ds-input>时,value不会触发回调,除非你在observedAttributes里写了'value' -
el.value = 'xyz'这类 JS property 赋值,永远不进attributeChangedCallback;想同步,得自己在 setter 里调this.setAttribute('value', val) - 布尔属性(如
disabled)的newValue是字符串"true"或null,不是布尔值,别直接if (newValue)判断
Shadow DOM 内部无法自动继承 :root CSS 变量
你在 或 :root 定义的 --primary-color,不会穿透进 shadowRoot。Shadow DOM 是样式边界,变量查找范围仅限自身内部。
- 错误写法:
color: var(--primary-color, #000);在 shadowRoot 的<style></style>里永远 fallback - 正确做法:在组件初始化时,手动从全局读取并注入到 shadowRoot,例如
this.shadowRoot.innerHTML = `<style>:host { --primary-color: ${getComputedStyle(document.documentElement).getPropertyValue('--primary-color')}; }</style>` - 更可持续的方式:要求所有主题色通过
data-属性传入,比如<ds-button data-theme="dark"></ds-button>,再在attributeChangedCallback里切换 class 或 CSS custom property
connectedCallback 只触发一次,滚动复用场景要自己接管
connectedCallback 在元素**首次挂载到主 DOM 树**时执行,之后移出又移回(比如虚拟滚动、display: none 切换),它不会再触发。
- 这意味着:组件内部状态(如输入框焦点、动画帧、定时器)不会自动重置或恢复
- 如果你依赖
connectedCallback初始化事件监听,那在disconnectedCallback里必须清理,否则内存泄漏 - 但
disconnectedCallback不可靠——元素可能被直接remove(),也可能被父节点innerHTML = ''清空,此时该回调根本不会执行;稳妥做法是在connectedCallback里加防重入判断,并把清理逻辑同时放在disconnectedCallback和外部生命周期管理中
真正让 UI 系统一致的,从来不是组件数量,而是每个 customElements.define() 调用背后是否有一份明确的接口文档:哪些属性可写、哪些事件可监听、哪些 CSS custom property 开放给外部定制、哪些内部结构严禁通过 slot 替换——这些约束一旦松动,ds- 前缀就只剩字面意义。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











