Appearance
React 插槽设计实现方案
痛点分析
React 本身没有提供原生的插槽(Slot)机制,这导致在构建可复用的布局组件时存在以下问题:
- 组件结构不灵活:父组件无法精确控制子内容的渲染位置
- 内容分发困难:无法像 Vue 那样通过
<template v-slot>
将内容分发到指定区域 - 布局复用受限:创建通用布局组件时,难以定义动态内容区域
解决方案:自定义插槽机制
核心思路
扩展虚拟 DOM 属性
- 在 React 元素上添加自定义
slot
属性,作为内容分发的标识符:
- 在 React 元素上添加自定义
子元素收集与转换
- 在父组件中获取
props.children
并转换为标准数组格式:
- 在父组件中获取
构建插槽映射表
- 遍历子元素数组,创建 slot 名称与元素的映射关系:
按插槽位置渲染
- 在组件布局中根据插槽名称精确渲染内容:
传递数据
- 通过
cloneElement
传递数据给插槽组件,实现数据传递:
js
const useSlot = (props) => {
let childrens = [];
if (props.children) {
if (Array.isArray(props.children)) {
childrens = props.children;
} else {
childrens = [props.children];
}
}
let slotMap = {};
childrens.forEach((children) => {
slotMap[children.props.slot || "default"] = children;
});
return slotMap;
};
function Layout(props) {
const slot = useSlot(props);
const userData = { title: "head" };
return (
<>
{/* 传递数据给header插槽 */}
{React.cloneElement(slots.head, { userData })}
{slot.middle}
{slot.tail}
{slot.default}
</>
);
}
export default function AppSlot() {
return (
<>
<Layout>
<h1>默认</h1>
<h1 slot="head" {...props}>
头部-{props.userData.title}
</h1>
<h1 slot="middle">中间</h1>
<h1 slot="tail">尾部</h1>
</Layout>
</>
);
}