exportparts 必须逐层显式声明且仅在 open Shadow DOM 中有效,大小写和拼写需与 part 属性严格一致,不支持通配符、动态绑定或伪类级联。

exportparts 必须逐层显式声明,不能跨层自动透传
多层 Shadow DOM 中,exportparts 不是“管道”,而是“接力棒”——每经过一层组件,都必须由该组件主动接住并重新抛出。比如 A → B → C,C 内部有 <button part="submit">,那么仅在 B 上写 exportparts="submit",A 是无法通过 A::part(submit) 直接命中按钮的。
真正生效的链路是:
- C 的 shadow 中:按钮带
part="submit" - B 的模板中:
<c-element exportparts="submit"></c-element>,且 B 自身 shadow 内需用:host ::part(submit)显式转发(否则 B 不会把 submit 暴露给上层) - A 的模板中:
<b-element exportparts="submit"></b-element>,此时 A 的 light DOM 才能写A::part(submit)
漏掉任意一层的 exportparts 声明,或大小写不一致(如 Submit ≠ submit),整条链就断了,::part() 选择器直接被浏览器忽略,连权重计算都不会触发。
exportparts 失效的首要排查点:Shadow Root mode 必须为 open
exportparts 在 mode: 'closed' 下完全无效——这不是兼容性问题,而是规范强制限制。浏览器对 closed Shadow Root 实施彻底屏蔽,外部连 shadowRoot 属性都读不到,更别说解析 exportparts 或匹配 ::part()。
立即学习“前端免费学习笔记(深入)”;
检查方式很简单:
- 在组件
constructor中确认调用了this.attachShadow({ mode: 'open' }) - 在 DevTools Elements 面板中展开该元素,能看到 shadow root 节点(而非显示
#shadow-root (closed)) - 若看到
(closed),立刻改回'open',否则所有透传逻辑都白搭
exportparts 值不是“通配符”,必须与 part 属性值严格一致
exportparts="header, footer" 只会让外部能用 ::part(header) 和 ::part(footer),但不会让 ::part(title) 生效,哪怕内部有个 <h1 part="title"> 却没列在 exportparts 里。
常见误操作:
- 拼写错误:内部写
part="btn",却在宿主写exportparts="button" - 大小写混用:内部
part="PrimaryButton",宿主写exportparts="primarybutton"(不匹配) - 动态绑定:试图用 JS 设置
el.exportparts = this.partList.join(',')——exportparts是 HTML 全局属性,只读取初始静态值,JS 修改无效
验证是否暴露成功:选中宿主元素,在 DevTools 的 Properties 面板里找 exportparts 属性值,它必须是字符串,且内容与内部 part 值逐字一致。
::part() 伪类本身不支持状态响应,得靠 :host() 配合
你不能写 my-button::part(submit):disabled { opacity: 0.5; }——::part() 后面跟伪类在所有浏览器中均被忽略。状态样式必须由组件内部用 :host([disabled]) ::part(submit) 控制。
这意味着两件事:
- 组件必须在
static get observedAttributes()中声明"disabled"等状态属性 - 必须在 shadow 内部的 style 标签中,用
:host([disabled]) ::part(submit)显式写出对应规则 - 外部只需设置
<my-button disabled>,浏览器就会触发匹配和重绘
漏掉 observedAttributes 声明,属性变了也不会触发 :host() 重匹配,样式就永远卡在初始状态。
最易被忽略的一点:exportparts 的“透传”本质是命名映射,不是样式继承。它不改变 CSS 特异性、不传递布局上下文、也不支持子选择器。写 my-card::part(header) .title 是无效的——::part() 是原子选择器,后面任何内容都会被丢弃。



















