# slot 模式
每个组件实例都拥有独立的 Shadow 树,代表组件自身模板中的节点结构。当组件的使用者在组件标签内放置子节点时,这些子节点会被视为 slot 内容,放置到 <slot> 的位置上。换句话说,<slot> 是一个占位符,代表 slot 内容所在的位置。
自定义组件使用 <slot> 时,slot 有三种工作模式可选。每个组件都可以任选其一。
- 单一 slot 是默认情况,仅支持一个
<slot>节点; - 多 slot 支持多个
<slot>,每个 slot 需要有一个名字<slot name="xxx">; - 动态 slot 支持在
wx:for内部使用<slot>,同时可以向 slot 内容节点树传递数据。
# 单一 slot
默认情况下激活的是单一 slot 模式。这种模式具有最优的性能。
在这个模式下,自定义组件 WXML 中只能包含一个 <slot> 节点。例如:
<!-- custom-component.wxml -->
<view>
<slot />
</view>
使用这个自定义组件时,传入内容节点:
<custom-component>
<view> content </view>
</custom-component>
<view> content </view> 最终会被放置到 <slot> 的位置上。
如果在自定义组件 WXML 内写了多个 <slot> 节点,只有第一个生效。
# 多 slot
在组件 options 中声明 multipleSlots: true 可激活多 slot 模式。
// Definition 形式的 custom-component.json
export default Component({
options: {
multipleSlots: true,
},
})
// Chaining 形式的 custom-component.json
export default Component()
.options({ multipleSlots: true })
.register()
多 slot 模式允许自定义组件 WXML 中包含多个 <slot> 节点。每个 <slot> 都必须有名字 name,其值必须是一个唯一的字符串。例如:
<!-- custom-component.wxml -->
<view class="foo-wrapper">
<slot name="foo" />
</view>
<view class="bar-wrapper">
<slot name="bar" />
</view>
在使用这个自定义组件时,需要为每个 slot 内容节点指定它所在的 slot 名字,例如:
<custom-component>
<!-- 这个 <view> 会放入 <slot name="foo"> 中 -->
<view slot="foo"> foo content </view>
<!-- 可以用 block 来避免额外生成一个 <view> -->
<block slot="bar"> bar content </block>
</custom-component>
# 静态 slot 的 slot 内容生命周期
单一 slot 和多 slot 模式统一称为静态 slot 模式。
在静态 slot 下,即使自定义组件没有 <slot> 节点,slot 内容节点依然会被创建并触发 attached detached 等生命周期。例如,如果在自定义组件里面这么写:
<!-- custom-component.wxml -->
<view wx:if="{{ cond }}">
<slot />
</view>
而在页面内这样写:
<custom-component>
<view> content </view>
<another-custom-component />
</custom-component>
如果 cond 为假,<slot> 节点就不存在,但是:
- 即使
<slot>节点不存在,<view> content </view>和<another-custom-component>仍然会被创建,<another-custom-component>的attached生命周期依然会被触发; - 如果后续
cond变成真,<slot>节点会被创建,但是<view> content </view>和<another-custom-component>并不会被重新创建,<another-custom-component>的attached生命周期也不会再次触发。
如果想要 slot 内容与 <slot> 节点一起创建或销毁,可以使用动态 slot 模式。
# 动态 slot
动态 slot 模式允许自定义组件使用若干个 <slot> 节点。
在组件 options 中声明 dynamicSlots: true 可激活动态 slot 模式。
// Definition 形式的 custom-component.json
export default Component({
options: {
dynamicSlots: true,
},
})
// Chaining 形式的 custom-component.json
export default Component()
.options({ dynamicSlots: true })
.register()
在使用动态 slot 时,每个 <slot> 拥有 slot 内容节点树的一份拷贝(这份拷贝会随着 <slot> 一同创建和销毁)。例如对于组件:
<!-- custom-component.wxml -->
<view class="foo">
<slot />
</view>
<view class="bar">
<slot />
</view>
在页面内这样写:
<custom-component>
<view> content </view>
</custom-component>
将会最终出现两个 <view> content </view>,分别位于 <view class="foo"> 和 <view class="bar"> 内部。
同时,<slot> 节点可以传递数据字段,让 slot 内容节点树使用。这使得动态 slot 非常适合 <slot> 节点出现在 wx:for 列表内部的情况。例如对于组件:
<!-- custom-component.wxml -->
<view wx:for="{{ list }}">
<slot list-index="{{ index }}" item="{{ item }}" />
</view>
通过 slot: 语法,在页面内可以接收到 list-index 和 item:
<custom-component>
<view slot:item> {{ item }} </view>
</custom-component>
使用 slot: 接收数据时,可以用 = 来指定一个别名。此外,还可以使用 <block> 来避免生成额外的节点:
<custom-component>
<block slot:listIndex="{{ i }}"> {{ i }} </block>
<block slot:item> {{ item }} </block>
</custom-component>
动态 slot 模式同样支持类似多 slot 的 name 属性,不过一般并不常用。