vue3 slots 插槽

vue3 slots 插槽是组件开发者预留给调用者自由发挥的区域,比如我们一个网页的顶部栏和左边菜单栏是固定的而中区域需要显示不同的内容,这时插槽就实现了模板的复用,插槽具有匿名插槽具名插槽作用域等特性。

匿名插槽

<!-- 子组件 slotsSetup.vue -->
<template>
  <div class="itxst">
    <div>顶部栏</div>
    <div>
      <div>菜单栏</div>
      <div>
        <!-- 下面的 slot 是一个匿名插槽-->
        <slot></slot>
      </div>
    </div>
  </div>
</template>
<script setup>
import { ref, reactive } from "vue";
</script>
<style scoped >
 /* 样式省略,请在试一试中查看样式 */
</style>

在父组件app.vue中使用子组件slotsSetup.vue的匿名插槽

<!-- 父组件 app.vue -->
<template>
  <!--父组件中使用匿名插槽-->
  <demo>
    <div>{{ text }}</div>
  </demo>
</template>
<script setup>
 import { ref } from "vue";
 import demo from "./slotsSetup.vue";
 const text = ref("我填充了demo组件的匿名插槽区域");
</script>

在线试一试

具名插槽

<!--组件名称 slotsSetup.vue -->
<template>
  <div class="itxst">
    <div>顶部栏</div>
    <div>
      <div>菜单栏</div>
      <div>
        <div>
          <!-- 名称为body的具名插槽-->
          <slot name="body"></slot>
        </div>
        <div>
          <!-- 名称为footer的具名插槽-->
          <slot name="footer"></slot>
        </div>
      </div>
    </div>
  </div>
</template>
<script setup>
import { ref, reactive } from "vue";
</script>
<style scoped >
 /* 样式省略,请在试一试中查看样式 */
</style>

在父组件app.vue中使用子组件slotsSetup.vue的具名插槽

<!--组件名称 app.vue -->
<template>
  <!--父组件中使用具名插槽-->
  <demo>
    <!--使用 body 插槽-->
    <template v-slot:body>
      {{body}}
    </template>
    <!--使用 footer 插槽-->
    <template v-slot:footer>
      {{footer}}
    </template>
  </demo>
</template>
 <script setup>
    import { ref } from "vue";
    import demo from "./slotsSetup.vue";
    const body = ref("我填充了demo组件的body区域");
    const footer = ref("我填充了demo组件的footer区域");
</script>

在线试一试

作用域

vue3 组件作用域的概念有点不大好解释,你可以通俗的认为在父组件使用插槽时访问子组件的数据

<!--组件名称 slotsSetup.vue -->
<template>
  <div class="itxst">
    <!--匿名插槽遍历websites数组,并把数据传给插槽  -->
    <template v-for="(item, index) in websites">
      <slot :item="item" :index="index"></slot>
    </template>
    <!--具名插槽footer 遍历websites数组,并把数据传给插槽  -->
    <template v-for="(item, index) in websites">
      <slot name="footer" :item="item" :index="index"></slot>
    </template>
  </div>
</template>
<script setup>
import { ref, reactive } from "vue";
const props = defineProps({
  websites: {
    type: Array,
    default: [],
  },
});
</script>
<style scoped >
.itxst {
  display: flex;
  flex-direction: column;
}
.itxst:deep(div) {
  border: solid 1px #ddd;
  padding: 6px;
  margin-bottom: 6px;
}
</style>

在父组件app.vue中访问子组件slotsSetup.vue的数据

<!--组件名称 app.vue -->
<template>
  <!--父组件中使用具名插槽-->
  <demo :websites="state.websites">
    <!-- 匿名插槽访问子组件的数据 -->
    <template v-slot="slotData">
      <div>{{ slotData.item.url }}</div>
    </template>
    <!--  具名插槽访问子组件的数据 -->
    <template v-slot:footer="slotData">
      <div>{{ slotData.item.url }}</div>
    </template>
  </demo>
</template>
 <script setup>
import { reactive } from "vue";
import demo from "./slotsSetup.vue";
const state = reactive({
  websites: [
    { id: 1, url: "https://www.itxst.com" },
    { id: 2, url: "google" },
    { id: 3, url: "baidu" },
    { id: 4, url: "bing" },
  ],
});
</script>

在线试一试