vue插槽

在 Vue 3 中,​​插槽(Slot)​​ 的机制与 Vue 2 类似,但语法和功能有所优化。以下是结合 Vue 3 特性的详细解释:

一、普通插槽:父传子

​场景​​:子组件定义占位符,父组件填充具体内容。 ​​数据流向​​:父组件 → 子组件 ​​示例​​:
<!-- 子组件 (ChildComponent.vue) -->
<template>
  <div>
    <slot>默认内容(当父组件未提供时显示)</slot>
  </div>
</template>

<script setup>
// 子组件无需额外逻辑,仅需定义插槽
</script>
<!-- 父组件 (ParentComponent.vue) -->
<template>
  <ChildComponent>
    <p>父组件传递的内容</p>
  </ChildComponent>
</template>

<script setup>
import ChildComponent from './ChildComponent.vue';
</script>
  • ​特点​​:
    • 子组件通过 <slot>定义占位符。
    • 父组件在子组件标签内填充内容,内容会替换子组件的 <slot>
    • 若父组件未提供内容,子组件的默认内容生效。

二、作用域插槽:子传父

​场景​​:子组件将数据传递给插槽,父组件基于数据自定义渲染。 ​​数据流向​​:子组件 → 父组件 ​​示例​​:
<!-- 子组件 (ListComponent.vue) -->
<template>
  <ul>
    <li v-for="item in items" :key="item.id">
      <!-- 将子组件数据传递给插槽 -->
      <slot :item="item" name="item">
        默认内容(当父组件未提供时显示)
      </slot>
    </li>
  </ul>
</template>

<script setup>
import { ref } from 'vue';

const items = ref([{ id: 1, name: "Apple" }]);
</script>
<!-- 父组件 (ParentComponent.vue) -->
<template>
  <ListComponent>
    <!-- 接收子组件传递的数据 -->
    <template #item="{ item }">
      <span>{{ item.name }}</span>
    </template>
  </ListComponent>
</template>

<script setup>
import ListComponent from './ListComponent.vue';
</script>
  • ​特点​​:
    • 子组件通过 v-bind将数据绑定到插槽(如 :item="item")。
    • 父组件通过 v-slot接收数据(如 #item="{ item }"),并自定义渲染逻辑。
    • 支持解构赋值,简化代码。

三、核心区别总结

类型数据流向功能Vue 3 语法特性
普通插槽 父 → 子 父组件控制子组件内部内容 使用 #default或省略名称
作用域插槽 子 → 父 → 子 子组件传递数据,父组件决定渲染方式 支持解构、动态插槽名(v-slot:[name]

四、常见误区澄清(Vue 3 版本)

1. ​​插槽本身是父传子​

  • ​正确性​​:普通插槽的占位符由子组件定义,但内容由父组件填充。
  • ​示例​​:
    <!-- 父组件 -->
    <ChildComponent>
      <p>父内容覆盖子组件插槽</p>
    </ChildComponent>
    • 若子组件未定义默认插槽,父组件内容会直接渲染到子组件根节点。

2. ​​作用域插槽是子传父的数据通道​

  • ​正确性​​:子组件通过插槽暴露数据,父组件接收后生成内容。
  • ​示例​​:
    <!-- 子组件 -->
    <slot :text="greeting"></slot>
    
    <!-- 父组件 -->
    <ChildComponent v-slot="{ text }">
      <div>{{ text }}</div>
    </ChildComponent>
    • 子组件通过 v-bind传递 greeting,父组件通过解构接收。

五、Vue 3 插槽新特性

1. ​<script setup>简化语法​

<!-- 子组件 -->
<script setup>
const props = defineProps(['items']);
</script>

<template>
  <ul>
    <li v-for="item in items" :key="item.id">
      <slot :item="item" />
    </li>
  </ul>
</template>

2. ​​动态插槽名​

<!-- 父组件 -->
<ChildComponent>
  <template #[dynamicSlotName]="slotProps">
    <!-- 动态渲染插槽内容 -->
  </template>
</ChildComponent>

3. ​​具名插槽的简写​

<!-- 父组件 -->
<ChildComponent>
  <template #header>头部内容</template>
  <template #footer>底部内容</template>
</ChildComponent>

六、实际应用场景(Vue 3 优化)

1. ​​列表组件​

<!-- 子组件 -->
<template>
  <ul>
    <li v-for="item in items" :key="item.id">
      <slot :item="item" name="item">
        <span>{{ item.name }}</span>
      </slot>
    </li>
  </ul>
</template>
<!-- 父组件 -->
<template>
  <ListComponent>
    <template #item="{ item }">
      <button @click="deleteItem(item.id)">删除</button>
      <span>{{ item.name }}</span>
    </template>
  </ListComponent>
</template>

2. ​​无渲染组件(逻辑封装)​

<!-- 子组件 -->
<script setup>
const { x, y } = useMousePosition();
</script>

<template>
  <slot :x="x" :y="y" />
</template>
<!-- 父组件 -->
<template>
  <MouseTracker>
    <template #default="{ x, y }">
      鼠标位置:{{ x }}, {{ y }}
    </template>
  </MouseTracker>
</template>

七、总结

  • ​普通插槽​​:父组件控制子组件内容,适合布局和结构定制。
  • ​作用域插槽​​:子组件传递数据,父组件决定渲染逻辑,适合动态内容生成。
  • ​Vue 3 优势​​:<script setup>简化代码、解构赋值提升可读性、动态插槽名增强灵活性。
通过合理使用插槽,可以实现组件的高度复用和灵活定制,同时保持逻辑与 UI 的解耦。
posted @ 2025-10-06 15:31  BKYNEKO  阅读(11)  评论(0)    收藏  举报