自定义元素必须先用customelements.define()注册,且标签名须含短横线(如my-button)、全小写、不与原生标签冲突;类须继承htmlelement并调用super(),shadow dom须在constructor中attachshadow一次;attributechangedcallback仅响应observedattributes声明的属性变更;slot实现内容分发,样式需置于shadow dom内。

直接写 <my-button></my-button> 不会生效,必须先用 customElements.define() 注册,否则只是个无行为的未知标签。
自定义元素名为什么必须带短横线
浏览器强制校验:不带短横线的名称(如 mybutton、Button、123)调用 customElements.define() 会立刻抛错:Failed to execute 'define' on 'CustomElementRegistry': The name "mybutton" is not a valid custom element name。
常见无效写法:
-
myButton(驼峰,缺短横线) -
-my-btn(短横线开头) -
my-btn-(短横线结尾) -
abc(纯字母,无短横线)
合法示例只有:my-button、data-input-field、x-slider——全小写 + 至少一个短横线 + 不在首尾。
constructor 里必须调用 super() 和 attachShadow()
这是初始化影子 DOM 的唯一安全时机。漏掉 super() 会导致实例无法正确继承 HTMLElement 行为;重复调用 attachShadow()(比如在 connectedCallback 里再调一次)会报错:Failed to execute 'attachShadow' on 'HTMLElement': This element already has a shadow root。
关键点:
-
this.attachShadow({ mode: 'open' })必须在constructor中执行,且只能一次 - 不要在
constructor里读this.innerHTML或this.getAttribute('xxx')—— 此时属性尚未解析完成 - 想访问初始属性值,改用
attributeChangedCallback,或等connectedCallback触发后再读
attributeChangedCallback 不触发?检查这三点
它不是“监听所有属性”,而是严格按 observedAttributes 声明的白名单响应,且仅对 HTML 属性变更(setAttribute、removeAttribute、标签内写死)有效。JS 直接赋值(如 el.disabled = true)完全不触发。
排查清单:
- 确认
static get observedAttributes()返回的是字符串数组,比如return ['loading', 'disabled'],不是对象或单个字符串 - 属性名大小写必须完全一致:
'loading'≠'Loading'≠'LOADING' - 避免在
constructor中就调用setAttribute—— 此时回调不会立即执行,要等元素真正挂载后才可能触发
<slot></slot> 是内容分发的刚需入口
没写 <slot></slot>,外部传入的文本或子节点就完全不可见。比如 <my-button>点击我</my-button>,若影子 DOM 里没 <slot></slot>,那“点击我”三个字就丢了。
基础用法:
- 单个默认插槽:
<slot></slot>,接收所有未命名子节点 - 具名插槽:
<slot name="icon"></slot>,对应外部<my-button><span slot="icon">★</span></my-button> - 不能在影子 DOM 外部用 CSS 选中插槽内容(如
my-button span),样式隔离是硬性限制
最易被忽略的一点:组件内部样式(<style></style>)必须写在影子 DOM 里,主文档的 <style></style> 对影子树内的元素完全无效——连 .my-class 都匹配不到。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











