Vue3插槽

发布于:2025-06-26 ⋅ 阅读:(15) ⋅ 点赞:(0)

一,概念

插槽(Slots)是一种强大的组件复用机制,用于实现组件的内容分发和复用。插槽是组件的特殊占位符,允许父组件向子组件插入自定义内容,其实就是用父组件的自定义内容替换掉这个特殊占位符。通过插槽,子组件可以定义自己的结构,同时允许父组件动态填充部分内容,实现组件的灵活复用。域插槽的核心价值在于将数据逻辑与视图渲染解耦,使组件更加灵活和可复用。通过子组件暴露数据,父组件自定义渲染,既保持了组件的通用性,又满足了个性化需求。在开发通用组件、列表、表单、状态管理等场景中,作用域插槽是必不可少的工具。

二,作用

  1. 内容分发 子组件通过 标签定义插槽位置,父组件可以在使用子组件时插入具体内容
  2. 组件复用 相同的子组件可以通过不同的插槽内容实现多样化展示
  3. 布局和数据解耦 将通用布局逻辑封装在子组件中,具体内容由父组件提供

三,类型

1. 默认插槽(匿名插槽)
子组件中未命名的标签,父组件插入的内容会默认填充到这里
Child.vue

<template>
  <h2>我是子组件的标题哈</h2>
  <div>
    <slot />
  </div>
</template>
<script setup></script>

App.vue

<template>
  <h1>我是父组件哈</h1>
  <child>
    <p>我是父组件给插槽的内容</p>
  </child>
</template>
<script setup>
import Child from './Child.vue'
</script>

2. 具名插槽
子组件中通过 name 属性命名的插槽,父组件可以通过 v-slot 或 # 语法指定内容填充位置
Child.vue

<template>
  <h2>我是子组件呀</h2>
  <div>
    <slot name='title'></slot><!-- 具名插槽:title -->
  </div>
  <slot/><!-- 默认插槽 -->
  <h3><slot name='content'></slot></h3><!-- 具名插槽:content -->
</template>
<script setup></script>

App.vue

<template>
  <h1>我是父组件哈</h1>
  <child>
    <template #title>
      <i>我是父组件给插槽的标题</i>
    </template>
    <p>我是默认插槽</p>
    <template #content>
      <i>我是父组件给插槽的内容</i>
    </template>
  </child>
</template>
<script setup>
import Child from './Child.vue'
</script>

3. 作用域插槽
一般插槽都是父组件提供内容,子组件无法传递数据给父组件用。但借助作用域插槽,父组件能够获取子组件的数据,进而依据这些数据对内容进行动态渲染。这种方式打破了传统插槽只能传递静态内容的局限。

场景1:列表组件的自定义渲染
需求:封装一个通用列表组件,允许父组件根据条件控制每一项的展示方式。子组件负责数据遍历和结构,父组件控制显示。
App.vue

<template>
  <h1>我是父组件哈</h1>
  <Child :items="users">
    <template #default="{ item }">
      <div class="user-card">
        <h3>{{ item.name }}</h3>
        <p>年龄:{{ item.age }}</p>
        <p v-if="item.sex === 'M'">性别:{{ item.sex }}</p>
      </div>
    </template>
	</Child>
</template>
<script setup>
import Child from './Child.vue'
import { ref } from 'vue'
  const users = ref([
  { id: 1, name: "张三", age: 25 ,sex:'M'},
  { id: 2, name: "李四", age: 30 ,sex:'F'},
  { id: 3, name: "王五", age: 22 ,sex:'M'}
]) 
</script>

Child.vue

<template>
  <ul>
    <li v-for="item in items" :key="item.id">
      <!-- 通过插槽暴露 item 数据 -->
      <slot :item="item"></slot>
    </li>
  </ul>
</template>

<script setup>
const props = defineProps({
  items: {
    type: Array,
    required: true
  }
})
</script>

示例2:表单组件的自定义控件
场景:封装一个表单组件,允许父组件自定义输入控件
可以在父组件中修改input插槽内容,改变表单输入控件
App.vue

<template>
  <h1>我是父组件哈</h1>
  <Child>
  <template #input="{ value, update }">
    <!-- 使用自定义输入控件 -->
    <input 
      type="text" 
      :value="value" 
      @input="update($event.target.value)" 
      placeholder="请输入内容"
    >
  </template>
</Child>
</template>
<script setup>
import Child from './Child.vue'
import { ref } from 'vue'
</script>

Child.vue

<template>
  <form @submit="handleSubmit">
    <slot name="input" :value="formValue" :update="updateValue"></slot>
    <button type="submit">提交</button>
  </form>
</template>

<script setup>
import { ref } from 'vue'
const formValue = ref('')

const updateValue = (newValue) => {
  formValue.value = newValue
}

const handleSubmit = () => {
  console.log('提交值:', formValue.value)
}
</script>

四,作用域插槽与普通插槽的对比

在这里插入图片描述

五,与$emit对比

作用域插槽和 emit 都能实现子组件向父组件传递数据,不过它们的应用场景和实现方式存在差异。
1.实现机制

  • 作用域插槽:子组件把数据以 v-slot 的形式暴露出来,父组件在使用子组件时,可以按需对这些数据进行处理和展示。
  • $emit 自定义事件:子组件借助 defineEmits 定义事件,再通过 emit 触发事件并传递数据,父组件监听该事件就能获取到数据。

2.应用场景

  • 作用域插槽:适用于子组件已经获取到数据,但要由父组件来决定如何渲染这些数据的情况,例如列表项的渲染。
  • $emit 自定义事件:适用于子组件发生某个事件(像点击、输入等)后,需要通知父组件做出响应的场景。

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到