customelements.define需含连字符且不可重复注册;样式须注入shadow dom内部;支持css自定义属性控制;attributechangedcallback不响应初始属性值;全站统一依赖接口契约而非单纯复用。

customElements.define 必须带连字符且不能重复注册
浏览器靠连字符(-)识别自定义标签,my-button合法,mybutton或MyButton会直接抛 DOMException: The element name must contain a hyphen。注册前不检查是否已存在,重复调用 customElements.define('nav-menu', NavMenu) 会报错;开发时建议加守卫:if (!customElements.get('nav-menu')) { customElements.define('nav-menu', NavMenu); }。
样式必须注入 Shadow DOM 内部,不能依赖外部 CSS
即使你在全局写了 nav-menu { display: block; },Shadow DOM 天然隔离,这条规则完全无效。所有样式得显式塞进 this.shadowRoot:
constructor() {
super();
this.attachShadow({ mode: 'open' });
const style = document.createElement('style');
style.textContent = `:host { display: block; } nav { background: #2c3e50; }`;
this.shadowRoot.appendChild(style);
this.shadowRoot.innerHTML += '<nav><slot></slot></nav>';
}
想让外部控制尺寸或主题色?用 CSS 自定义属性::host([size="large"]) { font-size: 1.4em; },再配合 <nav-menu size="large"></nav-menu>。
attributeChangedCallback 不响应初始 HTML 属性值
<nav-menu theme="dark"></nav-menu> 渲染时不会触发 attributeChangedCallback,除非你已在 static get observedAttributes() 中声明 theme,且该回调只对后续 setAttribute('theme', 'light') 这类操作生效。初始值同步得手动补:
- 在
connectedCallback里读一次this.getAttribute('theme') - 或在
attributeChangedCallback中判断oldValue === null时做初始化逻辑 - 注意:布尔属性如
disabled的newValue是字符串""或"disabled",不是布尔值
全站统一的关键不在“复用代码”,而在“约束契约”
写十个都叫 nav-menu 的组件没用,如果一个用 title 属性传标题,另一个用 label,一个发 menu-open 事件,另一个发 toggle,那就根本谈不上统一。真正起作用的是团队约定:
- 所有按钮类组件必须支持
disabled、size、variant属性 - 所有表单控件必须实现
formAssociated = true并桥接value和checked - 所有可展开组件必须用
expanded属性 +expand/collapse事件
没有这套接口层约束,Shadow DOM 再干净,也只是各自为政的“封装牢房”。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











