Vue的 slot 到底是个啥?老是记不住使用方法。今天就好好整理下这块知识。
Vue2 中 Slot 的实现原理与使用方法
一、Slot 的基本概念
Slot(插槽)是 Vue 组件化开发中用于内容分发的重要机制,允许父组件向子组件传递模板片段或 DOM 结构。Vue2 的插槽分为三种类型:
- 默认插槽:父组件传递的内容默认填充到子组件的 标签位置。
- 具名插槽:通过 name 属性标识插槽位置,实现精准分发。
- 作用域插槽:子组件向父组件传递数据,父组件基于子组件的数据渲染插槽内容。
二、Slot 的实现原理
Vue2 的插槽实现分为编译阶段和渲染阶段:
1. 编译阶段
- 父组件模板编译:
插槽内容会被编译为一个函数(
_t函数,即renderSlot),保存在子组件的$scopedSlots或$slots中。作用域插槽的内容被包装成的函数,接收子组件传递的数据作为参数。 - 子组件模板编译:
<slot>标签会被替换为_t函数调用,例如<slot name="header">会编译为 _t("header")。
2. 渲染阶段
普通插槽(默认插槽、具名插槽):
- 父组件的内容在父组件的作用域提前渲染,结果作为子组件的 $slots。
- 子组件通过 this.$slots[name] 获取对应的 VNode 并渲染。
作用域插槽:
- 父组件的内容延迟到子组件作用域中渲染,子组件通过
this.$scopedSlots[name](props)传递数据。 - 父组件接收数据并生成最终的 VNode。
3. 关键源码逻辑
- vm.$slots: 存储静态插槽内容(普通插槽)。
- vm.$scopedSlots: 存储作用域插槽函数。
- renderSlot(): 负责执行插槽函数并返回 VNode。
三、Slot 的使用方法
- 默认插槽
子组件:通过 <slot> 定义默认位置。
<!-- Child.vue -->
<template>
<div>
<slot>默认内容(可选)</slot>
</div>
</template>
父组件:直接传递内容到子组件标签内部。
<Child>
<p>这是父组件传递的内容</p>
</Child>
- 具名插槽
子组件:通过 指定插槽名称。
<!-- Child.vue -->
<template>
<div>
<slot name="header"></slot>
<slot></slot>
<slot name="footer"></slot>
</div>
</template>
父组件:通过 v-slot:name 或 #name 指定内容分发位置。
<Child>
<template v-slot:header>
<h1>这是头部</h1>
</template>
<p>这是默认内容</p>
<template #footer>
<p>这是底部</p>
</template>
</Child>
- 作用域插槽
子组件:在 <slot> 上绑定数据(类似 props)。
<!-- Child.vue -->
<template>
<div>
<slot :user="user">{{ user.name }}</slot>
</div>
</template>
<script>
export default {
data() {
return { user: { name: "Alice", age: 25 } };
},
};
</script>
父组件:通过 v-slot:default="props" 接收子组件数据。
<Child>
<template v-slot:default="slotProps">
<p>姓名:{{ slotProps.user.name }}</p>
<p>年龄:{{ slotProps.user.age }}</p>
</template>
</Child>
四、注意事项
- 作用域隔离:父组件模板中的插槽内容默认访问父组件数据,作用域插槽通过子组件传递数据。
- 语法兼容:Vue 2.6+ 推荐使用 v-slot 指令(缩写为 #),旧版 slot="name" 和 slot-scope 语法仍兼容。
- 性能优化:作用域插槽的函数特性可能导致子组件频繁更新,可通过缓存优化。
五、总结
- 原理核心:插槽本质是父组件内容编译为函数,子组件在渲染时调用函数并传入数据。
- 使用场景:
- 默认插槽:简单内容分发。
- 具名插槽:多区块内容分发。
- 作用域插槽:子组件数据驱动父组件内容渲染。
通过合理使用插槽,可以极大提升组件的灵活性和复用性。