customelements.define() 必须带破折号,否则抛 domexception;template 需 clonenode 才能渲染;data-* 属性须带业务前缀;shadow dom mode 选错将导致样式或访问异常。

customElements.define() 必须带破折号,否则注册直接失败
浏览器在调用 customElements.define() 时会强制校验标签名格式:不含破折号(如 mybutton、MyButton、my_button)会立刻抛出 DOMException: The element name is not valid。这不是兼容性问题,而是 HTML 规范层硬约束。
常见踩坑点包括:
- 复制示例代码时漏掉破折号,比如把
my-greeting写成mygreeting - 误把自定义元素当 class 使用:
<div class="my-button"> → 不触发组件逻辑,也不报错,但功能完全失效<li>在 Shadow DOM 内部用 <code>document.querySelector(".my-button")查找自身,实际应查this.shadowRoot.querySelector(".my-button__inner") - 在自定义元素构造函数中获取模板:
const tmpl = document.getElementById("user-card"); - 必须调用
tmpl.content.cloneNode(true),不能直接 appendtmpl - 挂载目标必须明确:用
this.attachShadow({ mode: "open" }).appendChild(...)或this.appendChild(...)(无 Shadow DOM 时) - 若模板含
<slot></slot>,需确保宿主 HTML 中有对应slot="xxx"属性,否则内容不透传 -
data-user-id="123"、data-api-source="user/profile"、data-user-status="active" - 配合
stylelint的selector-attribute-pattern规则,拒绝不含业务前缀的data-* - JS 中读取保持一致性:
el.dataset.userId对应data-user-id,但前提是命名本身有意义;el.dataset.id会返回undefined(因为data-id转驼峰后是id,不是Id) - 避免把多个字段塞进单个
data-state,更新一个字段就得重写整个属性值,增加竞态风险 -
mode: "closed"会屏蔽外部 CSS,且this.shadowRoot无法被外部 JS 访问(el.shadowRoot返回null),适合强封装场景,但调试困难 -
mode: "open"允许外部通过el.shadowRoot访问,也支持全局样式穿透(如:host .user-card__title),但需注意 CSS 选择器边界 ——.user-card__title只匹配 Shadow 内部节点,不匹配宿主元素上的同名 class - 若用了
adoptedStyleSheets注入样式表,必须确保 sheet 已创建且未被 GC;动态插入<style></style>到shadowRoot更稳妥 - 不要在 Shadow DOM 外部用
document.querySelector(".user-card__title")查找内部节点 —— 它根本查不到,这是 Shadow DOM 的设计目的
template 标签内容不会自动渲染,必须手动克隆并挂载
<template></template> 是惰性容器,其内容不会出现在 DOM 中,也不会触发脚本或样式解析。哪怕你写了 <template id="user-card"><div class="user-card">...</div></template>,不执行 JS 操作,它就只是个空壳。
正确做法是:
data-* 属性必须携带业务上下文,裸名等于没写
data-id="123" 看似简洁,实则埋雷——三个月后没人知道这是用户 ID、商品 SKU 还是订单流水号。它本质是前端与后端/业务逻辑的契约接口,必须显式声明来源和语义。
安全写法包括:
Shadow DOM 模式选错会导致样式穿透失败或意外隔离
Shadow DOM 的 mode 参数只有两个可选值:"open" 和 "closed"。默认是 "open",但很多开发者没意识到它对调试和样式继承的影响。
关键差异:
组件根节点 class 名漏写、data- 属性命名无上下文、customElements.define() 时机晚于 DOM 解析,这三处最容易被忽略,但只要其中一处出错,整个隔离机制就形同虚设。











