🤔 什么是插槽?
插槽(slot)是一种用于在组件中插入内容的机制。它允许组件的使用者在组件的标记中插入自定义的内容,从而增强组件的灵活性和可重用性。React中插槽实现的核心就是要用双闭合<Component>...</Component>调用组件。双闭合里传递的内容,都会作为变成虚拟DOM放在组件参数props的children属性中!
用人话来说,一个萝卜一个坑,插槽就相当于那个坑,你所想要自定义的内容,就是萝卜。
1️⃣ 具名插槽
具名插槽(named slots)是一种通过给插槽命名的方式来定义插槽的内容。
用上面的例子来说,就是给这个“坑”取个名字,比如说“A-坑”,那么只有”A-萝卜“才能进入这个坑,反之不能。
2️⃣ 匿名插槽
匿名插槽(unnamed slots)是指没有被命名的插槽。
用上面的例子来说,这个“坑”就是所有萝卜都能入驻。
🖥 如何用实现具名插槽?
1️⃣ 实现原理
因为父组件传递过来的children实际上是个虚拟dom。所以,只要在原来传递的children加上一些props作为标记,然后循环进行判定,就可得出对应的具名插槽。
⚠️注意:传过来的虚拟DOM可能只有1个,此时不为数组,这就需要我们去把children转化为数组。
2️⃣ 实现方法
import React from 'react'
/**
* ⭐️ 具名插槽 ⭐️
* 实现机制:因为父组件传递过来的children实际上是个虚拟dom。所以,只要在原来传递的children加
* 上一些props作为标记,然后循环进行判定,就可得出对应的具名插槽。
* ⚠️注意:传过来的虚拟DOM可能只有1个,此时不为数组,这就需要我们去把children转化为数组。
*/
const NamedSlot = (props) => {
// 获取传递过来的插槽内容
let children = React.Children.toArray(props?.children)
// 定义插槽名称
let firstSlot = [],
secondSlot = [],
defaultSlot = []
children.forEach(child => {
// 传递过来的插槽内容,都是编译为虚拟DOM,故只要去虚拟DOM里的props拿到对应的标记即可
let { slotName } = child.props
// 判断slotName属于哪一个位置
switch (slotName) {
case "firstSlot":
firstSlot.push(child);
break;
case "secondSlot":
secondSlot.push(child);
break;
default:
defaultSlot.push(child);
break;
}
})
return (
<React.Fragment>
<div>
{/* 这里放first */}
{
firstSlot.map(item => {
return item
})
}
</div>
<hr/>
<div>
{/* 这里放second */}
{
secondSlot.map(item => {
return item
})
}
</div>
<hr/>
<div>
{/* 这里放default */}
{
defaultSlot.map(item => {
return item
})
}
</div>
</React.Fragment>
)
}
export default NamedSlot
💻 如何用实现匿名插槽?
1️⃣ 实现原理
因为父组件传递过来的children实际上是个虚拟dom。所以,只要把原来的虚拟DOM遍历出来就好。
⚠️注意:传过来的虚拟DOM可能只有1个,此时不为数组,这就需要我们去把children转化为数组。
2️⃣ 实现方法
import React from 'react'
/**
* ⭐️ 匿名插槽 ⭐️
* 实现机制:因为父组件传递过来的children实际上是个虚拟dom。所以,只要把原来的虚拟DOM遍历出来
* 就好了。
* ⚠️注意:传过来的虚拟DOM可能只有1个,此时不为数组,这就需要我们去把children转化为数组。
*/
const UnnamedSlot = (props) => {
// 获取传递过来的插槽内容
let children = React.Children.toArray(props?.children)
return (
<React.Fragment>
{/* 直接遍历就好了 */}
{
children.map(item => {
return item
})
}
</React.Fragment>
)
}
export default UnnamedSlot
🧑🏻💻 使用效果
1️⃣ 目录结构
2️⃣ 组件使用
import React from 'react'
import NamedSlot from "./slotDemo/namedSlot";
import UnnamedSlot from "./slotDemo/unnamedSlot";
/**
* 插槽实现的核心就是要用双闭合的方式调用组件,然后把插槽内容传递过去。
*/
const SlotForReact = () => {
return (
<React.Fragment>
{/* 匿名插槽 */}
<div style={{marginLeft:24}}>
<h3>这里是匿名插槽</h3>
<UnnamedSlot>
<div>匿名-1</div>
<div>匿名-2</div>
<div>匿名-3</div>
<div>匿名-4</div>
<div>匿名-5</div>
</UnnamedSlot>
</div>
<hr/>
{/* 具名插槽 */}
<div style={{marginLeft:24}}>
<h3>这里是具名插槽</h3>
<NamedSlot>
<div slotName='firstSlot'>具名first-1</div>
<div slotName>具名default</div>
<div slotName='secondSlot'>具名second-1</div>
<div slotName='firstSlot'>具名first-2</div>
<div slotName='secondSlot'>具名second-2</div>
</NamedSlot>
</div>
</React.Fragment>
)
}
export default SlotForReact
3️⃣ 效果