自定义元素必须含连字符(如my-button)、禁止原生名;constructor仅初始化,DOM操作和属性读取须在connectedCallback中;样式需注入Shadow DOM内;attributeChangedCallback不触发初始值,需手动同步。

浏览器原生支持自定义 HTML 标签,不需要框架、不依赖构建工具,只要用 customElements.define() 注册,就能在 HTML 中直接写 <my-button></my-button> ——但注册失败、样式不生效、属性没响应,八成是卡在这几个关键点上。
自定义元素必须带连字符,且不能是保留名
浏览器靠连字符(-)区分原生标签和自定义标签。像 mybutton 或 MyButton 都会报错:Failed to execute 'define' on 'CustomElementRegistry': The name "mybutton" is not a valid custom element name。
-
my-button✅ 合法(含连字符、小写、非保留名) -
my_button❌ 不合法(下划线不被识别) -
div、button、slot❌ 所有原生标签名及html、body等全局名均禁止注册 -
x-button✅ 可用,但建议语义化,如nav-menu、date-picker
constructor 里只能初始化,不能操作 DOM 或读属性
很多新手在 constructor 里直接写 this.innerHTML = '...' 或 this.getAttribute('label'),结果发现属性读不到、DOM 没渲染、甚至报错 NotSupportedError: Failed to execute 'attachShadow' on 'HTMLElement'。
-
constructor只能调super()、创建 shadow root(this.attachShadow({ mode: 'open' }))、绑定事件或初始化私有字段 - 读属性、渲染模板、操作子节点,必须等到
connectedCallback触发后才安全 - 若需响应属性变化,要配合
static get observedAttributes()+attributeChangedCallback,否则label="xxx"传进来也无反应
样式隔离靠 Shadow DOM,但默认不继承外部 CSS
写了 this.attachShadow({ mode: 'open' }) 却发现字体、颜色、间距全丢了?因为 Shadow DOM 天然隔离样式 —— 外部 CSS 不会穿透进来,内部样式也不会漏出去。
立即学习“前端免费学习笔记(深入)”;
- 必须在
shadowRoot.innerHTML或shadowRoot.appendChild(styleEl)中显式注入样式 - 想让外部控制尺寸/主题色?用 CSS 自定义属性:
:host { display: inline-block; }控制宿主自身,:host([size="large"]) { font-size: 1.2em; }响应属性 - 不要指望
<style>body { color: red}</style>影响整个页面 —— 它只作用于 shadow 内部,且body根本不存在于 shadow 中
attributeChangedCallback 不会触发初始值,需手动同步
注册后首次渲染时,HTML 中写的 <my-input value="hello"></my-input>,attributeChangedCallback 并不会被调用 —— 它只响应后续的 JS 修改或 setAttribute,不处理初始解析。
- 初始属性值必须在
connectedCallback中用this.getAttribute('value')主动读取并应用 - 如果同时支持属性(
value)和 property(this.value = 'xxx'),记得双向同步:属性变 → 更新 property;property 变 → 调用this.setAttribute('value', ...) - 忘记同步会导致「HTML 写了 value,JS 读 this.value 却是 undefined」这类典型错觉
真正难的不是写完一个能跑的 <hello-world>,而是让属性更新、DOM 生命周期、样式边界、跨框架互操作这些隐性契约全部对齐 —— 浏览器不会报错,但行为会悄悄偏离预期。



















