slot属性必须写在light dom直接子元素上,且组件shadow dom中需有对应name的声明,否则内容静默丢失。

slot 属性必须写在 light DOM 直接子元素上
很多人把按钮包在 <div> 里再加 <code>slot="action",结果按钮根本不显示——slot 属性只对自定义元素的**直接子元素**生效,嵌套一层就失效。浏览器不会递归查找,也不会报错,只是静默丢弃内容。
正确写法只有这一种:
<my-card><br><button type="button" data-action="confirm" slot="action">确认</button><br></my-card>如果需要多个按钮,也得并列写:
<my-card><br><button type="button" data-action="confirm" slot="action">确认</button><br><button type="button" data-action="cancel" slot="action">取消</button><br></my-card>
-
slot值必须和组件 shadow DOM 中<slot name="action"></slot>的name完全一致(区分大小写) - 没匹配到的元素会留在 light DOM 中不渲染,也不进任何
<slot></slot> - 同一个
slot名下多个元素,按 DOM 顺序拼接,不是覆盖
卡片组件 shadow DOM 里必须显式声明 <slot name="action"></slot>
光在外部写 slot="action" 没用。组件内部必须在 shadowRoot 里放对应 <slot name="action"></slot>,否则内容无处可去。常见错误是只写了默认 <slot></slot>,结果所有带 slot 属性的按钮都消失。
示例(在 connectedCallback 或构造函数中):
this.attachShadow({ mode: 'open' });<br>this.shadowRoot.innerHTML = `<br><div class="card">
<br><header><slot name="title"></slot></header><br><main><slot></slot></main><br><footer><slot name="action"></slot></footer><br>
</div>`;
- 没声明
name="action"的<slot></slot>,外部写的slot="action"就彻底丢失 - 默认插槽(无
name)只能有一个,且不能和具名插槽混用在同一层级分发逻辑中 -
<slot></slot>里可以写 fallback 文字,比如<slot name="action">暂无操作</slot>
按钮事件必须委托到卡片根元素或用 slotchange 监听
动态插入的按钮(比如通过 innerHTML 或模板克隆生成)无法直接绑定事件——它们可能还没挂载,或被多次销毁重建。硬写 onclick 在按钮上不仅难维护,还会漏掉后续新增实例。
推荐做法:
class MyCard extends HTMLElement {<br> connectedCallback() {<br> this.addEventListener('click', this._handleClick.bind(this));<br> }<br><br> _handleClick(e) {<br> if (e.target.matches('button[data-action]')) {<br> const action = e.target.dataset.action;<br> this.dispatchEvent(new CustomEvent('card-action', { detail: { action } }));<br> }<br> }<br>}
- 别在
<slot></slot>内部写内联onclick,语义混乱且无法复用 - 监听
slotchange也可用于响应插槽内容变更,但仅适用于内容替换,不适用于初始绑定 - 移动端注意:确保按钮有足够触控热区,
min-width: 44px+padding是底线
样式穿透限制:父组件无法直接控制 slot 里的按钮样式
你在 my-card 的 shadow CSS 里写 my-card::slotted(button),只能影响直接塞进 <my-card></my-card> 的按钮;如果按钮是封装在 <my-button></my-button> 里再传进来的,这个样式完全无效——它属于子组件的 light DOM,不在当前 shadow root 范围内。
所以要么:
• 让按钮保持裸露(最简可控)
• 让子组件暴露 ::part(button) 并由父组件用 my-button::part(button) 控制
• 或干脆把按钮样式规则写进按钮自身(比如加 class="card-action-btn")
-
::slotted()只作用于当前 shadow root 下直接分发的内容 - 不要指望靠父组件 CSS 强行覆盖深层嵌套按钮的
background或color - 按钮重置必须做全:
border: none; background: none; padding: 0; font: inherit;,否则跨浏览器表现不一致
slot 属性位置和 shadow DOM 中 <slot></slot> 声明的严格配对——差一个字母、多一层包裹、少一个 name,内容就无声无息地消失了,连控制台都不会提醒。











