html 中的 element 标签从未标准化,仅是已废弃的 web components 实验提案;自定义元素必须用 customelements.define() 注册且含短横线,constructor 中须调 super() 和 attachshadow(),slot 是内容分发唯一出口,外部 css 无法穿透影子 dom。

element 标签从未被标准化,也从未进入 HTML 规范 —— 它只是早期 Web Components 草案中的一个实验性提案,2014 年后就被彻底移除。你现在在任何现代浏览器里写 <element></element>,它都只是个无意义的未知标签,不会触发任何自定义行为。
customElements.define() 是唯一注册方式
所有合法的自定义元素必须通过 customElements.define() 显式注册,且名称必须含短横线(如 my-button),否则会立刻抛错:Failed to execute 'define' on 'CustomElementRegistry': The name "mybutton" is not a valid custom element name。
- 注册前写
<my-button></my-button>不报错,但也不会执行类逻辑 —— 它只是个空壳节点 - 注册必须在 DOM 解析完成前或
DOMContentLoaded事件中完成,不能晚于元素首次出现在 HTML 中 - 同一个名字只能注册一次;重复调用
customElements.define()会直接抛NotSupportedError
constructor 中必须调用 super() 和 attachShadow()
影子 DOM 不是可选功能,而是封装的基础。漏掉 super() 会导致实例无法继承 HTMLElement 的原型方法(比如 getAttribute 失效);漏掉 this.attachShadow({ mode: 'open' }) 或重复调用,都会让组件失去样式隔离能力或直接崩溃。
-
attachShadow()只能在constructor中调用一次,不能挪到connectedCallback里 - 不要在
constructor里读this.innerHTML或this.getAttribute('xxx')—— 此时属性尚未解析,值全为null - 想初始化带默认值的属性,改用
static get observedAttributes()+attributeChangedCallback,或等connectedCallback触发后再读
slot 是内容分发的唯一出口
没有 <slot></slot>,外部传入的文本、子元素就完全不可见。比如写 <my-card>标题</my-card>,但组件内部没写 <slot></slot>,那“标题”两个字就彻底消失。
-
<slot></slot>必须放在影子 DOM 内,不能写在 light DOM 里 - 支持具名插槽:
<slot name="header"></slot>对应<my-card><h2 slot="header">标题</h2></my-card> - 样式穿透限制:外部 CSS 无法直接选中影子 DOM 内部节点,除非用
::slotted(*)或:host伪类
真正容易被忽略的是生命周期与属性同步的时机差 —— constructor 里拿不到属性,connectedCallback 里 DOM 已挂载但可能还没渲染完成,而 attributeChangedCallback 只响应 HTML 属性变更,不响应 JS 属性赋值。这些不是 bug,是设计使然。写的时候得按这个节奏来,别硬套 React/Vue 的思维。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











