跳转到内容

4. 插槽

插槽允许父组件为消费方(consumer)插入的内容预留占位。

具名插槽

父组件(Card.sharq):

xml
<template>
<ui:VisualElement $MainElement class="card">
    <slot name="header" />
    <ui:VisualElement class="card__body">
        <slot /> <!-- default — slot without name -->
    </ui:VisualElement>
    <slot name="footer" />
</ui:VisualElement>
</template>

消费方:

xml
<sus:Card>
    <!-- v-slot:header → falls into <slot name="header"> -->
    <template v-slot:header>
        <ui:Label text="Card Header" style="font-size: 18px;" />
    </template>

    <!-- Without v-slot → falls into <slot /> (default) -->
    <ui:Label text="Main content goes here" />

    <!-- v-slot:footer → hits <slot name="footer"> -->
    <template v-slot:footer>
        <sus:SusButton text="OK" />
    </template>
</sus:Card>

SlotPropMap

csharp
public class SlotPropMap : Dictionary<string, object>
{
    // Passes data from the parent slot to the consumer
}

工作原理

编译器会在父组件中生成:

csharp
var __slot_header = GetSlotContainer("header");
this.Add(__slot_header);
BuildSlot("header", null, __slot_header);

var __slot_default = GetSlotContainer("default");
this.Add(__slot_default);
BuildSlot("default", null, __slot_default);

在消费方中:

csharp
RegisterSlotContent("header", __el, null);

为插槽容器设置样式

GetSlotContainer() 返回一个真实的 VisualElement,它位于模板中包裹 <slot> 的元素内部。 它带有两个固定的 USS 类:

  • sus-slot — 每个插槽容器都有;
  • sus-slot--<name> — 例如 sus-slot--headersus-slot--default

容器本身不附带任何布局(UI Toolkit 默认值:flex-direction: column)。因此设置为行方向的 外层元素只会影响这一个盒子本身——被投影的子元素仍然会垂直排列。需要在容器上重复设置方向:

css
.my-card__actions { flex-direction: row; align-items: center; }
.my-card__actions > .sus-slot { flex-direction: row; align-items: center; }

不要依赖类型选择器(> VisualElement)来实现这一点——真正的约定是这个类。