插槽是干啥的
插槽 就是 组件中的一个 占位符,
这个占位符 可以接收 父组件 传递过来的 html 的模板值,然后进行填充渲染。
就这么简单,插槽就是干这个的。
要说它的优点吧,基本上就是可以使子组件的内容可以被父组件控制,显得更加灵活。
插槽的关键字
slot
: 就是定义插槽的关键字。
插槽的几个小分类
插槽从使用的特点上,可以分为以下几个小类:
1、普通插槽 : 没有任何特殊性,最常规的那种;
2、默认值插槽 : 自带默认值的插槽,父组件没有传值时,会自动渲染默认值;
3、具名插槽 : 顾名思义,就是带名字的插槽,在组件中存在多个插槽时较为常用;
4、作用域插槽 : xxxxxx
插槽的使用案例
下面的案例,基本上包含了插槽常见的使用操作。
1、最简单的使用
【子组件】中声明 <slot></slot> 插槽;
【父组件】中使用组件的时候,直接传入相应的值。
子组件
<template>
<!-- 子组件 -->
<div class="childdiv">
子组件 - msg : {{ msg }}
<br>
<!-- 声明一个插槽 -->
<slot></slot>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
// 声明一个变量
const msg = ref('这是子组件的msg变量')
</script>
<style scoped>
.childdiv{
width: 300px;
border: 1px solid green;
}
</style>
父组件
<template>
<div class="basediv">
父组件msg : {{ msg }}
<br>
<br>
<!-- 使用子组件 : 传入 内容,子组件的插槽中进行渲染 -->
<ChildComponent >
<span style="color: green;">这是父组件给子组件插槽中传递的内容</span>
</ChildComponent>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
// 引入子组件
import ChildComponent from './ChildComponent.vue'
// 声明父组件的一个变量
const msg = ref('这是父组件的msg变量')
</script>
<style scoped>
.basediv{
width: 400px;
height: 200px;
border: 1px solid red;
}
</style>
运行结果
2、带默认值的插槽
在<slot></slot> 标签中填写一些内容,就是它的默认值;
当父组件没有传值时,会渲染默认值;
当父组件传值时,会渲染父组件传递过来的值。
子组件
<template>
<!-- 子组件 -->
<div class="childdiv">
子组件 - msg : {{ msg }}
<br>
<!-- 声明一个插槽 : 是一个带有默认值的插槽-->
<slot>
<span style="color: rgb(126, 0, 128);">子组件中插槽的默认值</span>
</slot>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
// 声明一个变量
const msg = ref('这是子组件的msg变量')
</script>
<style scoped>
.childdiv{
width: 300px;
border: 1px solid green;
}
</style>
父组件
<template>
<div class="basediv">
父组件msg : {{ msg }}
<br>
<br>
<!-- 使用子组件 : 不传值,子组件会渲染插槽的默认值 -->
<ChildComponent />
<br>
<!-- 使用子组件 : 传入 内容,子组件的插槽中进行渲染 -->
<ChildComponent >
<span style="color: green;">这是父组件给子组件插槽中传递的内容</span>
</ChildComponent>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
// 引入子组件
import ChildComponent from './ChildComponent.vue'
// 声明父组件的一个变量
const msg = ref('这是父组件的msg变量')
</script>
<style scoped>
.basediv{
width: 400px;
height: 200px;
border: 1px solid red;
}
</style>
运行效果
3、具名插槽
组件中如果存在多个插槽,那么给插槽起个名字是一个不错的选择;
一方面在组件内容可以很好地对插槽进行区分;
另一方面,在父组件中使用插槽时,也可以指定名称使用插槽,比较明确。
具名插槽的定义格式 : <slot name="插槽名称"></slot>
具名插槽的使用方式1 : <template v-solt:插槽名称">xxx</template>
具名插槽的使用方式2 : <template #插槽名称">xxx</template>
【注意点】
具名插槽 和 默认插槽可以同时存在;
默认插槽 会被自动命名为 “default”;
* 父组件在使用子组件的具名插槽时,建议 使用 <template> 标签将内容包起来。
* 当子组件 同时接收到 具名插槽 和 默认插槽时,所有的位于 子组件 直接标签下的 节点,都会默认传给 默认插槽!
* 父组件在使用子组件的插槽时,同一个插槽只能写一遍,否则会报错 (具名插槽和默认插槽都不可以重复使用)。
子组件 : 包含 【具名插槽】 和 【默认插槽】
<template>
<!-- 子组件 -->
<div class="childdiv">
子组件 - msg : {{ msg }}
<br>
<!-- 声明第一个具名插槽 -->
<slot name="slotname1"></slot>
<!-- 声明第二个具名插槽 -->
<slot name="slotname2"></slot>
<!-- 声明第一个默认插槽 -->
<slot ></slot>
<!-- 声明第二个默认插槽 -->
<slot ></slot>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
// 声明一个变量
const msg = ref('这是子组件的msg变量')
</script>
<style scoped>
.childdiv{
width: 350px;
border: 1px solid green;
}
</style>
父组件 : 使用 子组件的【具名插槽】 和 【默认插槽】
<template>
<div class="basediv">
父组件msg : {{ msg }}
<br>
<br>
<!-- 使用子组件-->
<ChildComponent />
<br>
<!-- 使用子组件 : 传入 内容,子组件的插槽中进行渲染 -->
<ChildComponent >
<!-- 使用具名插槽1 : 写法1 : v-solt:插槽名-->
<template v-slot:slotname1>
具名插槽 slotname1 : 父组件给子组件传的值 <br><br>
</template>
<!-- 使用具名插槽2 : 写法2 : #插槽名-->
<template #slotname2>
具名插槽 slotname2 : 父组件给子组件传的值 <br><br>
</template>
<!-- 使用默认插槽1 : 写法1 : #default : 推荐这种写法,比较明确-->
<template #default>
匿名插槽 : 父组件给子组件传的值 <br><br>
</template>
<!-- 使用默认插槽2 : 写法2 : 在 子组件标签下的直接的节点,会直接渲染在默认插槽中-->
<!-- <span style="color: green;">这是父组件给子组件默认插槽中传递的内容<br></span> -->
</ChildComponent>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
// 引入子组件
import ChildComponent from './ChildComponent.vue'
// 声明父组件的一个变量
const msg = ref('这是父组件的msg变量')
</script>
<style scoped>
.basediv{
width: 400px;
height: 200px;
border: 1px solid red;
}
</style>
运行效果
4、作用域插槽
在上面的案例中,插槽中能够访问的只是【父组件】中的变量,而无法直接渲染【子组件】中的变量值;
尽管 带默认值的 插槽 可以将 【子组件】中的变量放进去,但 当【父组件】传值后,会将 默认值 覆盖,也无法保留【子组件】中的变量值;
作用域
插槽就可以实现 将【子组件】想要暴露出去的变量值传递给 【父组件】,【父组件】再将变量的值放到 插槽中,进而实现 渲染 【子组件】的变量的功能。
由于
默认插槽
和具名插槽
的编码方式不同,因此本小结将分开描述具体的写法。
4.1 只有默认插槽的使用案例
子组件
: 通过 props 将属性暴露出去
父组件
:在 【子组件】的标签上,直接使用 v-slot 指令 接收暴露出来的属性
子组件
<template>
<!-- 子组件 -->
<div class="childdiv">
子组件 - msg : {{ msg }}
<br>
<!-- 声明一个默认插槽 : 并通过属性暴露出去两个属性 -->
<slot :aName="a" :bName="b"></slot>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
// 声明一个变量
const msg = ref('这是子组件的msg变量')
// 声明两个属性-暴露出去
const a = ref('这是第一个属性')
const b = ref(100)
</script>
<style scoped>
.childdiv{
width: 350px;
border: 1px solid green;
}
</style>
父组件
<template>
<div class="basediv">
父组件msg : {{ msg }}
<br>
<br>
<!-- 使用子组件 : 传入 内容,子组件的插槽中进行渲染 -->
<ChildComponent v-slot="childProps">
【父组件中接收到了子组件暴露出来的属性】:<br>
{{ childProps }}
</ChildComponent>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
// 引入子组件
import ChildComponent from './ChildComponent.vue'
// 声明父组件的一个变量
const msg = ref('这是父组件的msg变量')
</script>
<style scoped>
.basediv{
width: 400px;
height: 200px;
border: 1px solid red;
}
</style>
运行结果
4.2 只有具名插槽的使用案例
父组件在使用子组件的具名插槽时,
需要在 slot 的名称后面接收子组件暴露出来的属性。
语法格式1 :v-slot:name="propsName"
语法格式2 :#name="propsName"
子组件
<template>
<!-- 子组件 -->
<div class="childdiv">
子组件 - msg : {{ msg }}
<br>
<!-- 声明一个具名插槽 -->
<slot name="slotname1" :aName1="a" :aName2="b"> </slot>
<!-- 声明一个具名插槽 -->
<slot name="slotname2" :bName1="a" :bName2="b"></slot>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
// 声明一个变量
const msg = ref('这是子组件的msg变量')
// 声明两个属性-暴露出去
const a = ref('这是第一个属性')
const b = ref(100)
</script>
<style scoped>
.childdiv{
width: 350px;
border: 1px solid green;
}
</style>
父组件
<template>
<div class="basediv">
父组件msg : {{ msg }}
<br>
<br>
<!-- 使用子组件 : 传入 内容,子组件的插槽中进行渲染 -->
<ChildComponent >
<!-- 使用具名插槽1 : 写法1 : v-solt:插槽名-->
<template v-slot:slotname1="propsObj1">
父组件静态文本1 : 第一种写法<br>
{{ propsObj1 }}
</template>
<!-- 使用具名插槽2 : 写法2 : #插槽名-->
<template #slotname2="propsObj2">
父组件静态文本2 : 第二种写法<br>
{{ propsObj2 }}
</template>
</ChildComponent>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
// 引入子组件
import ChildComponent from './ChildComponent.vue'
// 声明父组件的一个变量
const msg = ref('这是父组件的msg变量')
</script>
<style scoped>
.basediv{
width: 400px;
height: 200px;
border: 1px solid red;
}
</style>
运行结果
4.3 默认插槽和具名插槽的混合使用案例
当 子组件中同时具有 具名插槽和 默认插槽 还需要给 父组件 暴露属性时,
默认插槽 的方式要 与 具名插槽的方式一致,即 使用默认的名称default
也就是需要使用<template>
标签将内容包起来
子组件
<template>
<!-- 子组件 -->
<div class="childdiv">
子组件 - msg : {{ msg }}
<br>
<!-- 声明一个具名插槽 -->
<slot name="slotname2" :bName1="a" :bName2="b"></slot>
<!-- 声明一个默认插槽 : 并通过属性暴露出去两个属性 -->
<slot :cName1="a" :cName2="b"></slot>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
// 声明一个变量
const msg = ref('这是子组件的msg变量')
// 声明两个属性-暴露出去
const a = ref('这是第一个属性')
const b = ref(100)
</script>
<style scoped>
.childdiv{
width: 350px;
border: 1px solid green;
}
</style>
父组件
<template>
<div class="basediv">
父组件msg : {{ msg }}
<br>
<br>
<!-- 使用子组件 : 传入 内容,子组件的插槽中进行渲染 -->
<ChildComponent >
<!-- 使用具名插槽2 : 写法2 : #插槽名-->
<template #slotname2="propsObj2">
具名插槽: 使用#语法糖的格式指定具名插槽<br>
{{ propsObj2 }}
</template>
<!-- 使用默认插槽1 : 写法1 : #default-->
<template #default="propsObj3">
匿名插槽 : 要与具名插槽的写法保持一致 <br>
{{ propsObj3 }}
</template>
</ChildComponent>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
// 引入子组件
import ChildComponent from './ChildComponent.vue'
// 声明父组件的一个变量
const msg = ref('这是父组件的msg变量')
</script>
<style scoped>
.basediv{
width: 400px;
height: 200px;
border: 1px solid red;
}
</style>
运行结果
以上就是 组件中 插槽的主要内容。