vue3的插槽slots

普通插槽

父组件使用子组件时,在子组件闭合标签中提供内容模板,插入到子组件定义的出口的地方

在这里插入图片描述

Test.vue


<template>
    父组件: start - {{ parentMsg }}
    <br/>
    <fancy-button>
    	                        <!-- 注意点: 这里是默认插槽内容,如果使用template标签来包裹的话, 
    	                                    就必须加上#default,否则不会渲染出来 -->
        点我解锁 {{ parentMsg }} <!-- 插槽内容 -->
                                <!-- 插槽内容是可以使用父模板中定义的数据 -->
                                <!-- 插槽内容无法访问子组件的数据 -->
                                <!-- 父组件模板中的表达式只能访问父组件的作用域;
                                     子组件模板中的表达式只能访问子组件的作用域。 -->
    </fancy-button>
    
    <fancy-button>
        						<!-- 未提供插槽内容给插槽, 子组件中的插槽将使用插槽中的默认内容 -->
    </fancy-button>
    <br/>
    父组件: end
</template>

<script lang="ts" setup>
import FancyButton from './FancyButton.vue';
const parentMsg = 'halo parent'

</script>
<style lang="scss"></style>

FancyButton.vue

<template>
    子组件: start - {{ sonMsg }}
    <br/>
    <button>
        <slot>默认内容: {{ sonMsg }}</slot> <!-- 插槽出口 -->
        					               <!-- 当没有提供插槽内容的情况下, 就展示“默认内容” -->
    </button>
    <br/>
    子组件: end
</template>

<script lang="ts" setup>

const sonMsg = 'halo son'

</script>

<style lang="scss">

</style>
  

具名插槽

在一个组件中可以定义多个插槽出口slot,每个插槽出口slot可以使用name属性标识插槽名,称为具名插槽(没有提供 name 的 <slot> 出口会隐式地命名为“default”
在这里插入图片描述

Test.vue

<template>
    <BaseLayout>

        <template v-slot:header>    <!-- 将会把这块插入到BaseLayout组件中定义的名为header的插槽中 -->
            <p>-{{ parentMsg }}-</p><!-- 如果BaseLayout组件中定义了多个名为header的插槽, 则每个都会插入 -->
        </template>                 <!-- 可以将v-slot:header简写为 #header -->


        <template #default>          <!-- 将 v-slot:default 简写为 #default -->
            <p>+默认内容+</p>         <!-- 默认插槽可以不使用template包裹, 直接写即可,
                                          这是因为当一个组件同时接收默认插槽和具名插槽时,
                                          所有位于顶级的非 <template> 节点都被隐式地视为默认插槽的内容
                                      -->
        </template>

        <template v-slot:[pos]>       <!-- 动态插槽名, 当通过下面changePos修改pos值时, 插槽内容会切换到不同地方 -->
            <span>*{{ parentMsg }}*</span>
        </template>

    </BaseLayout>
    <hr/>
    <button @click="changePos">切换动态插槽名{{pos}}</button>
    

</template>

<script lang="ts" setup>
	import { ref, reactive } from 'vue'
	import BaseLayout from '@/views/test/BaseLayout.vue'
	
	const parentMsg = ref('parentMsg')
	const pos = ref('footer')
	const changePos = ()=>{
	    if(pos.value === 'footer'){
	        pos.value = 'outer'
	    } else {
	        pos.value = 'footer'
	    }
	}
</script>
<style lang="scss"></style>

BaseLayout.vue

<template>
    <div class="container">
        <header>
            <slot name="header"></slot> <!-- 这里会插入 -->
            <slot name="header"></slot> <!-- 这里同样会插入 -->
        </header>
        <main>
            <slot></slot>
        </main>
        <footer>
            <slot name="footer">{{ '父组件不提供的话,就展示: ' + footerContent }}</slot>
        </footer>
    </div>
    outer----<slot name="outer">{{ '父组件不提供的话,就展示: ' + outerContent }}</slot>
</template>

<script lang="ts" setup>
    import { ref,reactive } from 'vue'
    const footerContent = ref('footerContent')
    const outerContent = ref('outerContent')
</script>

<style lang="scss"></style>

作用域插槽

父组件中定义的插槽的内容无法访问到子组件的数据,但是我们需要一种方法来让子组件在渲染时将一部分数据提供给插槽。

默认插槽

在这里插入图片描述

Test.vue
<template>
									<!-- 因为这里只使用了一个默认插槽,所以可以把v-slot=slotProps写在组件的位置 -->
    <BaseLayout v-slot="slotProps"> <!-- 拿到子组件提供给插槽的数据, 
                                         ,默认省略了default, 即:本来是v-slot:default="slotProps"
                                         ,可以直接在这里解构 -->
                                    <!-- 注意: 这里使用默认插槽的情况下,不能使用template标签将下面内容包裹 -->
        {{ parentMsg }}  <!-- 本身就可以访问到父组件自身的数据 -->
        {{ slotProps }}  
        {{ slotProps.count }}
    </BaseLayout>
</template>

<script lang="ts" setup>
import { ref, reactive } from 'vue'
import BaseLayout from './BaseLayout.vue';
const parentMsg = ref('parentMsg')

</script>
<style lang="scss"></style>

或如下

<template>
    <BaseLayout>

        <template v-slot:default="slotProps"> <!-- 这里可省略为#default="slotProps" -->
            {{ parentMsg }}  <!-- 本身就可以访问到父组件自身的数据 -->
            {{ slotProps }}  
            {{ slotProps.count }}
        </template>
            
    </BaseLayout>
</template>

<script lang="ts" setup>
import { ref, reactive } from 'vue'
import BaseLayout from './BaseLayout.vue';
const parentMsg = ref('parentMsg')

</script>
<style lang="scss"></style>
BaseLayout.vue
<template>
    <div>
    	<!-- 向插槽的出口上传递 属性及值-->
        <slot :text="greetMsg" :count="1"></slot>
    </div>
</template>

<script lang="ts" setup>
    import { ref,reactive } from 'vue'
    const greetMsg = ref('打招呼')
</script>

<style lang="scss"></style>

具名作用域插槽

在这里插入图片描述

Test.vue
<template>
    <BaseLayout>

        <template #default="defaultProps">
            {{ parentMsg }}  <!-- 本身就可以访问到父组件自身的数据 -->
            {{ defaultProps }}  
            {{ defaultProps.count }}
        </template>
            
        <template #title="{name,age}">
            title - {{ parentMsg }}
            title - {{ name }} - {{ age }}
        </template>

    </BaseLayout>
</template>

<script lang="ts" setup>

	import { ref, reactive } from 'vue'
	import BaseLayout from './BaseLayout.vue';
	const parentMsg = ref('parentMsg')

</script>
<style lang="scss"></style>
BaseLayout.vue
<template>
    <div>
        <slot :text="greetMsg" :count="1"></slot>

        <br/>
        
        <slot name="title" v-bind="person" v-for="person in persons"></slot>
    </div>
</template>

<script lang="ts" setup>
    import { ref,reactive } from 'vue'
    const greetMsg = ref('打招呼')

    const persons = [{name:'zzhua',age:18},{name:'zj',age:22}]
</script>

<style lang="scss"></style>

复杂插槽示例

  1. 插槽可以通过父组件传值的方式,在子组件中动态生成(如:Test.vue中,传给了MySlot2.vue子组件一个sls属性,MySlot2.vue子组件遍历该属性生成3个插槽)
  2. 插槽可以放入子组件中引入的组件中,作为引入组件的插槽内容(如:MySlot2.vue子组件动态生成的插槽,放入MySlot2.vue子组件中,作为插槽内容)
  3. 插槽中通过属性绑定的数据可以在对应的插槽内容中获取

在这里插入图片描述

Test.vue

<template>
    
    <div>In Test.vue</div>

	<!-- 传给MySlot1, 用于动态生成插槽 -->
    <MySlot1 :sls="sls">

		<!-- 将插槽内容按照插槽名,放入动态生成插槽中对应名字的插槽中 -->
        <template #slotA="pN"> <!-- pN是取得插槽传入的数据(的对象) -->
            MySlot1-slotA - {{ pN }}
        </template>

        <template #slotB="pN">
            MySlot1-slotB - {{ pN }}
        </template>

        <template #slotC="pN">
            MySlot1-slotC - {{ pN }}
        </template>

    </MySlot1>

</template>

<script lang="ts" setup>
    import { ref,reactive } from 'vue'
    import MySlot1 from './MySlot1.vue';
    const sls = reactive([{slotName:'slotA'}, {slotName:'slotB'}, {slotName:'slotC'}])
</script>

<style lang="scss">
    
</style>

MySlot1.vue

<template>
    
    <div>In MySlot1.vue-start</div>

    <MySlot2>
    	<!-- 将整个内容,作为MySlot2子组件的default插槽内容 -->
    	<!-- #default="{personName}" 表示里面的数据由插槽提供 -->
        <template #default="{ personName }">
        	<!-- 通过for循环,动态生成插槽 -->
            <slot :pN="personName" :name="sl.slotName" v-for="(sl, index) in sls" :key="index"></slot>
        </template>
    </MySlot2>
    
    <div>In MySlot1.vue-end</div>


</template>

<script lang="ts" setup>
    import { ref,reactive } from 'vue'
    import MySlot2 from './MySlot2.vue';

    defineProps(['sls'])

</script>

<style lang="scss">

</style>

MySlot2.vue

<template>

    <div>In MySlot2.vue - start</div>
    <div class="my-slot2-slot">
        <slot :personName="mySlot2Data.name"></slot>
    </div>
    <div>In MySlot2.vue - end</div>
    
</template>

<script lang="ts" setup>
    import { ref,reactive } from 'vue'
    const mySlot2Data = reactive({'name':'zzhua'})
</script>

<style lang="scss">
    .my-slot2-slot {
        color: blue;
    }
</style>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值