vue3:插槽、具名插槽、条件插槽、作用域插槽、具名作用域插槽 一次性搞清楚 --- 通俗易懂

1、插槽的使用:

~父组件index.vue:

<h3>我是父组件testSlot</h3>
<!-- 调用子组件alertBox测试插槽 -->
<alertBox></alertBox>
<alertBox>
    Something good will be happened.
/alertBox>
<br>

~alertBox.vue:

<template>
  <h3>我是子组件alertBox</h3>
  <div class="alert-box">
    <strong>This is a good news for this week!!!!!</strong>
    <!-- 插槽占位,父组件调用时加入特性数据,展示特定数据 -->
    <slot>
      <!-- 我们使用 <slot> 作为一个占位符,父组件传递进来的内容就会渲染在这里。 -->
    </slot>
  </div>
</template>

效果:

2、封装button组件,通过slot插槽传入按钮名称 

~父组件index.vue:

<div>##################封装button组件,通过slot插槽传入按钮名称 start #############</div>
        <div>调用fancyButton按钮组件</div>
        <br>
        <FancyButton class="fancy-btn">Click me!</FancyButton>
        <FancyButton>提交订单</FancyButton>
        <FancyButton class="examine-btn">提交审核</FancyButton>
        <FancyButton>{{ obj.btn_text }}</FancyButton>
        <br>
        <div>##################封装button组件,通过slot插槽传入按钮名称 end #############</div>
const obj = reactive({
    productName: 'Fancy',
    total: 99,
    sku_id: '10086',
    btn_text: '去支付'
})
<style lang="less" scoped>

.container {

    h3 {
        text-align: center;
    }

    .fancy-btn {
        margin-right: 10px;
    }

    .examine-btn:hover {
        background-color: #A802DB;
        font-size: 16px;
    }
}

</style>

 ~fancyBuuton.vue:

<template>
    <button class="fancu-btn">
        <slot></slot>
    </button>
</template>

<script setup>
import { ref, reactive } from 'vue'

/**
 * 封装统一风格的按钮样式
 * 稍微有不同的可以通过 透传 attribute
 * “透传 attribute”指的是传递给一个组件,却没有被该组件声明为 props 或 
 * emits 的 attribute 或者 v-on 事件监听器。最常见的例子就是 class、style 和 id。
 * 详情看官网:https://cn.vuejs.org/guide/components/attrs.html
 */
</script>

<style scoped>
.fancu-btn {
    background-color: #42F5E2;
    border-radius: 25px;
    font-size: 14px;
    cursor: pointer;
    outline: none;
}
</style>

效果:

3、具名插槽

~父组件index.vue:

        <NamedSlots>
            <template #header>
                <h4>Here might be a page title</h4>
            </template>
            <!-- 两种写法效果相同 -->
            <!-- <template #default>
                <p>A paragraph for the main content.</p>
                <p>And another one.</p>
            </template> -->
            <p>A paragraph for the main content.</p>
            <p>And another one.</p>
            <template #footer>
                <h4>底部信息</h4>
                <p>Here's some concat info.</p>
            </template>
        </NamedSlots>

 ~namedSlot.vue:

<template>
  <div class="container">
    <header>
      <!-- 标题内容放这里 -->
      <slot name="header"></slot>
    </header>
    <main>
      <!-- 主要内容放这里 ——不添加name,是默认插槽-->
      <slot></slot>
    </main>
    <footer>
      <!-- 底部内容放这里 -->
      <slot name="footer"></slot>
    </footer>
  </div>
</template>
<script setup>
import { ref, reactive } from 'vue'
/**
 * 具名插槽 --- 有时在一个组件中包含多个插槽出口是很有用的。
 * Named slots
 * 这类带 name 的插槽被称为具名插槽 (named slots)。没有提供 name 的 <slot> 出口会隐式地命名为“default”。
 * 要为具名插槽传入内容,我们需要使用一个含 v-slot 指令的 <template> 元素,并将目标插槽的名字传给该指令:
 * v-slot 有对应的简写 #,因此 <template v-slot:header> 可以简写为 <template #header>。其意思就是“将这部
 * 分模板片段传入子组件的 header 插槽中”。
 */

</script>
<style scoped>

</style>

效果:

 4、条件插槽

~父组件index.vue:

        <div>##################条件插槽 start #############</div>
        <ConditionalSlot>
            <template #header>
                <h4>头部数据</h4>
            </template>
            <template #default>
                <p>主要内容:Here is the content.</p>
            </template>
            <template #footer>
                <em>底部信息:Here is the footer!</em>
            </template>
        </ConditionalSlot>
        <div>##################条件插槽 end #############</div>

conditionalSlot.vue:

<template>
  <div class="card">
    <div class="card-header">
        <slot name="header"></slot>
    </div>
    <div class="card-content">
        <slot />
    </div>
    <div class="card-footer">
        <slot name="footer"></slot>
    </div>
  </div>
</template>
<script setup>
import { ref, reactive } from 'vue'
/**
 * 条件插槽
 * 有时你需要根据插槽是否存在来渲染某些内容。
 * 你可以结合使用 $slots 属性与 v-if 来实现。
 * 在下面的示例中,我们定义了一个卡片组件,它拥有三
 * 个条件插槽:header、footer 和 default。 当 header、
 * footer 或 default 存在时,我们希望包装它们以提供额外的样式:
 * 
 */

</script>
<style lang="less" scoped>
  .card {
    border: 1px solid black;
    padding: 0;
    .card-header {
        background-color: skyblue;
        padding: 4px;
    }
    .card-content {
        background-color: pink;
        padding: 4px;
    }
    .card-footer {
        background-color: lightgray;
        padding: 4px;
    }
  }
</style>

效果:

5、动态插槽名:

       <!-- 动态插槽名
        动态指令参数在 v-slot 上也是有效的,即可以定义下面这样的动态插槽名: -->
        <!-- <base-layout>
            <template v-slot:[dynamicSlotName]>
                ...
            </template>
            可缩写为如下:
            <template #[dynamicSlotName]>
                ...
            </template>
        </base-layout> -->

 6、作用域插槽:

~父组件index.vue:

<div>##################作用域插槽 start #############</div>
        <br>
        <!-- 通过v-slot接收传过来的数据 -->
        <scopeSlot v-slot="props">
            message:{{ props.text }}
            count:{{ props.count }}
        </scopeSlot>
        <!-- 
            v-slot="slotProps" 可以类比这里的函数签名,和函数的参数类似,我们也可以在 v-slot 中使用解构:
         -->
         <scopeSlot v-slot="{ text, count }">解构后的数据:'{{ text }}', 和 '{{ count }}''</scopeSlot>
        <br>
        <div>##################作用域插槽 end #############</div>

scopeSlot.vue:

<template>
  <div class="container">
    <header>
      <!-- 标题内容放这里 -->
      <slot name="header"></slot>
    </header>
    <main>
      <!-- 主要内容放这里 ——不添加name,是默认插槽-->
      <slot></slot>
    </main>
    <footer>
      <!-- 底部内容放这里 -->
      <slot name="footer"></slot>
    </footer>
  </div>
</template>
<script setup>
import { ref, reactive } from 'vue'
/**
 * 具名插槽 --- 有时在一个组件中包含多个插槽出口是很有用的。
 * Named slots
 * 这类带 name 的插槽被称为具名插槽 (named slots)。没有提供 name 的 <slot> 出口会隐式地命名为“default”。
 * 要为具名插槽传入内容,我们需要使用一个含 v-slot 指令的 <template> 元素,并将目标插槽的名字传给该指令:
 * v-slot 有对应的简写 #,因此 <template v-slot:header> 可以简写为 <template #header>。其意思就是“将这部
 * 分模板片段传入子组件的 header 插槽中”。
 */

</script>
<style scoped>

</style>

 效果:

7、具名作用域插槽

~父组件index.vue:

    <div>##################具名作用域插槽 start #############</div>
        <!-- 解构或者通过变量接收参数都可以 -->
         <NamedScopeSlot v-slot:header="{msg}">具名作用域插槽数据:{{ msg }}</NamedScopeSlot>
         <!-- 等同于下面 -->
         <NamedScopeSlot #header="{msg}">具名作用域插槽数据:{{ msg }}</NamedScopeSlot>
         <!-- 注意插槽上的 name 是一个 Vue 特别保留的 attribute,不会作为 props 传递给插槽。因此最终 headerProps 的结果是 { message: 'hello' }。 -->
         <NamedScopeSlot #header="{name, msg}">具名作用域插槽数据:{{ name }} {{ msg }}</NamedScopeSlot>
         
     <div>##################具名作用域插槽 end #############</div>

namedScopeSlot.vue:

<template>
  <div>
    <!-- 具名作用域插槽 -->
    <slot name="header" msg="Hello, Friday"></slot>
  </div>
</template>
<script setup>
import { ref, reactive } from 'vue'

</script>
<style scoped>

</style>

效果:

以上就是插槽的使用,源码里面有注释说明。 

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值