根据官网做的Vue3插槽小结

84 阅读3分钟
// 看到v-slot:xxx 代表的是具名插槽,可以简写为#xxx
// 看到v-slot="xxx" 代表的是默认作用域插槽
// 看到v-slot:name="xxx" 代表的是具名作用域插槽,可以简写为#name="xxx"
// 作用域插槽实际上就是子组件为父组件通过slot标签提供数据,在父组件中进行展示使用,子组件提供数据,父组件提供格式
// 作用域插槽使用不管是默认作用域插槽还是具名作用域插槽,最好都配合template标签使用
// 默认作用域插槽: <template v-slot="slotProps">{{ slotProps }}</template>
// 具名作用域插槽: <template v-slot:jmSlot="slotProps">{{ slotProps }}</template>
// 具名作用域插槽简写: <template #jmSlot="slotProps">{{ slotProps }}</template>

一、默认插槽

  1. 子组件默认不提供内容,具体数据模板样式由父组件提供
<!-- Child.vue -->
<template>
  <div class="cpn">
    <slot></slot>
  </div>
</template><script setup>
</script><style>
.cpn {
  padding: 1.5rem;
  background: #fff;
}
</style><!-- Parent.vue -->
<template>
  <div class="parent_box">
    <h2>我是父组件</h2>
    <default-slot>
      <h2>我是父组件提供的默认插槽标题</h2>
      <p>我是父组件提供的默认插槽内容</p>
    </default-slot>
  </div>
</template><script setup>
import DefaultSlot from './components/DefaultSlot.vue';
</script><style>
.parent_box {
  padding: 1.5rem;
  background: #bfa;
}
</style>

image.png 2. 子组件提供内容,父组件无内容时,默认展示子组件内容

<!-- Child.vue -->
<template>
  <div class="cpn">
    <slot>
      <h2>我是子组件提供的插槽标题</h2>
      <p>我是子组件提供的插槽内容</p>
    </slot>
  </div>
</template><script setup>
</script><style>
.cpn {
  padding: 1.5rem;
  background: #fff;
}
</style><!-- Parent.vue -->
<template>
  <div class="parent_box">
    <h2>我是父组件</h2>
    <default-slot></default-slot>
  </div>
</template><script setup>
import DefaultSlot from './components/DefaultSlot.vue';
</script><style>
.parent_box {
  padding: 1.5rem;
  background: #bfa;
}
</style>

image.png

  1. 子组件提供内容,父组件有内容时,展示父组件内容
<!-- Child.vue -->
<template>
  <div class="cpn">
    <slot>
      <h2>我是子组件提供的插槽标题</h2>
      <p>我是子组件提供的插槽内容</p>
    </slot>
  </div>
</template><script setup>
</script><style>
.cpn {
  padding: 1.5rem;
  background: #fff;
}
</style><!-- Parent.vue -->
<template>
  <div class="parent_box">
    <h2>我是父组件</h2>
    <default-slot>
      <h2>我是父组件提供的默认插槽标题</h2>
      <p>我是父组件提供的默认插槽内容</p>
    </default-slot>
  </div>
</template><script setup>
import DefaultSlot from './components/DefaultSlot.vue';
</script><style>
.parent_box {
  padding: 1.5rem;
  background: #bfa;
}
</style>

image.png

二、具名插槽

  1. 子组件只有具名插槽且不提供内容时,父组件内容需要使用template标签搭配v-slot:具名插槽名称使用,v-slot: 可以简写为#
<!-- Child.vue -->
<template>
  <div class="cpn">
    <slot name="jmSlot1"></slot>
    <slot name="jmSlot2"></slot>
  </div>
</template><script setup>
</script><style>
.cpn {
  padding: 1.5rem;
  background: #fff;
}
</style>
<!-- Parent.vue -->
<template>
  <div class="parent_box">
    <h2>我是父组件</h2>
    <name-slot>
      <template v-slot:jmSlot1>
        <h2>我是父组件提供的具名插槽标题1</h2>
        <p>我是父组件提供的具名插槽内容1</p>
      </template>
      <template #jmSlot2>
        <h2>我是父组件提供的具名插槽标题2</h2>
        <p>我是父组件提供的具名插槽内容2</p>
      </template>
    </name-slot>
  </div>
</template><script setup>
import NameSlot from './components/NameSlot.vue';
</script><style>
.parent_box {
  padding: 1.5rem;
  background: #bfa;
}
</style>

image.png

  1. 子组件同时拥有具名插槽和默认插槽时
<!-- Child.vue -->
<template>
  <div class="cpn">
    <slot name="jmSlot"></slot>
    <slot></slot>
  </div>
</template><script setup>
</script><style>
.cpn {
  padding: 1.5rem;
  background: #fff;
}
</style><!-- Parent.vue -->
<template>
  <div class="parent_box">
    <h2>我是父组件</h2>
    <name-slot>
      <template #jmSlot>
        <h2>我是父组件提供的具名插槽标题</h2>
        <p>我是父组件提供的具名插槽内容</p>
      </template>
      <p>我是默认插槽内容</p>
    </name-slot>
  </div>
</template><script setup>
import NameSlot from './components/NameSlot.vue';
</script><style>
.parent_box {
  padding: 1.5rem;
  background: #bfa;
}
</style>

image.png

三、作用域插槽 => 将子组件的数据通过插槽传递给父组件,在父组件模板展示使用

  1. 默认作用域插槽,直接在子组件标签上使用v-slot="slotProps"或者在子组件内部使用template搭配v-slot使用,即可拿到子组件通过插槽传递过来的数据
<!-- Child.vue -->
<template>
  <div class="cpn">
    <slot
      :count="count"
      :msg="msg"
    ></slot>
  </div>
</template><script setup>
import { ref } from 'vue';
const count = ref(0);
const msg = ref('scope_slot_default');
</script><style>
.cpn {
  padding: 1.5rem;
  background: #fff;
}
</style><!-- Parent.vue -->
<template>
  <div class="parent_box">
    <h2>我是父组件</h2>
    <!-- 写法一:直接在子组件标签上写v-slot -->
    <scope-slot-default v-slot="slotProps">{{ slotProps }}</scope-slot-default>
    <!-- 写法二:写在子组件标签内部template标签上搭配v-slot -->
    <scope-slot-default>
      <template v-slot="slotProps">{{ slotProps }}</template>
    </scope-slot-default>
  </div>
</template><script setup>
import ScopeSlotDefault from './components/ScopeSlotDefault.vue';
</script><style>
.parent_box {
  padding: 1.5rem;
  background: #bfa;
}
</style>

image.png

  1. 具名作用域插槽,需要搭配template模板使用
<!-- Child.vue -->
<template>
  <div class="cpn">
    <slot
      name="jmSlot"
      :info="info"
    ></slot>
  </div>
</template><script setup>
import { ref, reactive } from 'vue';
const info = reactive({
  name: 'zs',
  age: 24
})
</script><style>
.cpn {
  padding: 1.5rem;
  background: #fff;
}
</style>
<!-- Parent.vue -->
<template>
  <div class="parent_box">
    <h2>我是父组件</h2>
    <scope-slot>
      <template #jmSlot="slotProps">
        <p>{{ slotProps }}</p>
      </template>
    </scope-slot>
  </div>
</template><script setup>
import ScopeSlot from './components/ScopeSlot.vue';
</script><style>
.parent_box {
  padding: 1.5rem;
  background: #bfa;
}
</style>

image.png

  1. 默认作用域插槽和具名作用域插槽组合使用
<!-- Child.vue -->
<template>
  <div class="cpn">
    <!-- 默认作用域插槽 -->
    <slot
      :count="count"
      :msg="msg"
    ></slot>
    <!-- 具名作用域插槽 -->
    <slot
      name="jmSlot"
      :info="info"
    ></slot>
  </div>
</template><script setup>
import { ref, reactive } from 'vue';
const count = ref(0);
const msg = ref('scope_slot_default');
const info = reactive({
  name: 'zs',
  age: 24
})
</script><style>
.cpn {
  padding: 1.5rem;
  background: #fff;
}
</style>
<!-- Parent.vue -->
<template>
  <div class="parent_box">
    <h2>我是父组件</h2>
    <scope-slot>
      <template v-slot="slotProps1">
        <p>{{ slotProps1 }}</p>
      </template>
      <template #jmSlot="slotProps2">
        <p>{{ slotProps2 }}</p>
      </template>
    </scope-slot>
  </div>
</template><script setup>
import ScopeSlot from './components/ScopeSlot.vue';
</script><style>
.parent_box {
  padding: 1.5rem;
  background: #bfa;
}
</style>

image.png