JavaScript中如何使用插槽
在JavaScript的组件化开发中,插槽(Slot)是实现内容分发的核心机制,它允许我们在组件内部预留占位区域,在使用组件时动态传入自定义内容。这一特性在Vue、React等框架中都有体现,不同框架的实现方式略有差异,下面我们分别介绍主流框架中的插槽用法。
Vue中的插槽使用
Vue对插槽的支持非常完善,分为默认插槽、具名插槽和作用域插槽三类,下面逐一说明。
默认插槽
默认插槽是最基础的插槽形式,组件内部用<slot>标签预留位置,使用时传入的内容会替换该<slot>标签。
首先定义带默认插槽的子组件:
<!-- 子组件 ChildComponent.vue -->
<template>
<div class="child-container">
<h3>子组件标题</h3>
<!-- 默认插槽,未传入内容时显示默认文本 -->
<slot>这是插槽的默认内容</slot>
</div>
</template>
<script>
export default {
name: 'ChildComponent'
}
</script>
<style scoped>
.child-container {
border: 1px solid #ccc;
padding: 16px;
margin: 8px 0;
}
</style>然后在父组件中使用该子组件,传入自定义内容:
<!-- 父组件 ParentComponent.vue -->
<template>
<div class="parent-container">
<h2>父组件</h2>
<!-- 不传入内容,使用子组件插槽默认内容 -->
<ChildComponent />
<!-- 传入自定义内容,替换子组件默认插槽 -->
<ChildComponent>
<p>这是父组件传入的自定义内容</p>
<button>点击按钮</button>
</ChildComponent>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue'
export default {
name: 'ParentComponent',
components: {
ChildComponent
}
}
</script>具名插槽
当组件需要多个插槽时,可以通过给<slot>添加name属性定义具名插槽,使用时通过v-slot指令指定要替换的插槽名称。
先修改子组件,添加多个具名插槽:
<!-- 子组件 ChildComponent.vue -->
<template>
<div class="child-container">
<header>
<!-- 名为header的具名插槽 -->
<slot name="header">默认头部内容</slot>
</header>
<main>
<!-- 默认插槽,等价于 name="default" -->
<slot>默认主体内容</slot>
</main>
<footer>
<!-- 名为footer的具名插槽 -->
<slot name="footer">默认底部内容</slot>
</footer>
</div>
</template>
<script>
export default {
name: 'ChildComponent'
}
</script>父组件中使用具名插槽:
<!-- 父组件 ParentComponent.vue -->
<template>
<div class="parent-container">
<ChildComponent>
<!-- v-slot:header 可简写为 #header -->
<template #header>
<h3>自定义头部标题</h3>
</template>
<!-- 默认插槽内容 -->
<p>这是自定义的主体内容,会替换默认插槽</p>
<template #footer>
<p>自定义底部信息 © 2024</p>
</template>
</ChildComponent>
</div>
</template>作用域插槽
作用域插槽允许子组件向父组件传递数据,父组件在使用插槽时可以根据子组件传递的数据渲染内容。
子组件中通过给<slot>绑定属性传递数据:
<!-- 子组件 ChildComponent.vue -->
<template>
<div class="child-container">
<h3>用户列表</h3>
<ul>
<li v-for="user in userList" :key="user.id">
<!-- 向父组件传递user数据 -->
<slot name="user" :userInfo="user">
{{ user.name }} - {{ user.age }}岁
</slot>
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'ChildComponent',
data() {
return {
userList: [
{ id: 1, name: '张三', age: 25 },
{ id: 2, name: '李四', age: 28 },
{ id: 3, name: '王五', age: 22 }
]
}
}
}
</script>父组件中接收作用域插槽传递的数据:
<!-- 父组件 ParentComponent.vue -->
<template>
<div class="parent-container">
<ChildComponent>
<!-- 接收子组件传递的userInfo数据,解构赋值获取 -->
<template #user="{ userInfo }">
<span style="color: #1890ff">
{{ userInfo.name }}(年龄:{{ userInfo.age }})
</span>
</template>
</ChildComponent>
</div>
</template>React中的插槽实现
React本身没有内置的插槽语法,通常通过props.children来实现类似插槽的内容分发功能,也可以自定义props来模拟具名插槽。
通过children实现默认插槽
子组件通过props.children获取父组件传入的子元素,实现默认插槽的效果:
// 子组件 ChildComponent.jsx
import React from 'react';
const ChildComponent = (props) => {
return (
<div style={{ border: '1px solid #ccc', padding: '16px', margin: '8px 0' }}>
<h3>子组件标题</h3>
{/* 渲染父组件传入的内容,等价于默认插槽 */}
{props.children || <p>这是插槽的默认内容</p>}
</div>
);
};
export default ChildComponent;父组件使用:
// 父组件 ParentComponent.jsx
import React from 'react';
import ChildComponent from './ChildComponent';
const ParentComponent = () => {
return (
<div>
<h2>父组件</h2>
{/* 不传入children,使用默认内容 */}
<ChildComponent />
{/* 传入自定义children,替换默认内容 */}
<ChildComponent>
<p>这是父组件传入的自定义内容</p>
<button onClick={() => alert('点击了按钮')}>点击按钮</button>
</ChildComponent>
</div>
);
};
export default ParentComponent;自定义props模拟具名插槽
React中可以通过给子组件传递不同名称的props,模拟具名插槽的效果:
// 子组件 ChildComponent.jsx
import React from 'react';
const ChildComponent = (props) => {
return (
<div style={{ border: '1px solid #ccc', padding: '16px' }}>
<header>
{/* 渲染header插槽内容,无内容则显示默认 */}
{props.header || <p>默认头部内容</p>}
</header>
<main>
{/* 渲染主体内容 */}
{props.children || <p>默认主体内容</p>}
</main>
<footer>
{/* 渲染footer插槽内容 */}
{props.footer || <p>默认底部内容</p>}
</footer>
</div>
);
};
export default ChildComponent;父组件中使用:
// 父组件 ParentComponent.jsx
import React from 'react';
import ChildComponent from './ChildComponent';
const ParentComponent = () => {
return (
<div>
<ChildComponent
header={<h3>自定义头部标题</h3>}
footer={<p>自定义底部信息 © 2024</p>}
>
<p>这是自定义的主体内容</p>
</ChildComponent>
</div>
);
};
export default ParentComponent;原生Web Components中的插槽
Web Components规范原生支持插槽,通过<slot>标签实现,和Vue的默认插槽、具名插槽逻辑类似。
首先定义自定义元素:
// 定义自定义元素
class MyCard extends HTMLElement {
constructor() {
super();
// 创建影子DOM,隔离样式
const shadow = this.attachShadow({ mode: 'open' });
// 创建卡片容器
const container = document.createElement('div');
container.style.border = '1px solid #ccc';
container.style.padding = '16px';
container.style.margin = '8px 0';
// 添加标题区域
const title = document.createElement('h3');
title.textContent = '卡片标题';
container.appendChild(title);
// 添加默认插槽
const defaultSlot = document.createElement('slot');
defaultSlot.textContent = '这是插槽的默认内容';
container.appendChild(defaultSlot);
// 添加具名插槽
const footer = document.createElement('div');
footer.style.marginTop = '12px';
const footerSlot = document.createElement('slot');
footerSlot.name = 'footer';
footerSlot.textContent = '默认底部内容';
footer.appendChild(footerSlot);
container.appendChild(footer);
shadow.appendChild(container);
}
}
// 注册自定义元素
customElements.define('my-card', MyCard);在HTML中使用该自定义元素:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Web Components插槽示例</title>
</head>
<body>
<my-card>
<p>这是传入的默认插槽内容</p>
<!-- 具名插槽内容,通过slot属性指定 -->
<p slot="footer">自定义底部信息</p>
</my-card>
<script src="my-card.js"></script>
</body>
</html>插槽使用注意事项
- Vue中的作用域插槽数据传递是单向的,父组件只能读取子组件传递的数据,无法直接修改。
- React的children可以是任意合法的React节点,包括字符串、数字、元素、数组等,使用时需要做非空判断避免报错。
- Web Components的
<slot>标签只在影子DOM中生效,普通DOM中不会解析该标签。 - 插槽内容的作用域属于父组件,子组件无法直接访问插槽内的变量,作用域插槽就是为了解决这个问题。
JavaScript插槽Vue插槽React childrenWeb Components组件内容分发 本作品最后修改时间:2026-05-23 23:16:03