一、什么是插槽
插槽就是子组件中的提供给父组件使用的一个占位符,用<slot></slot>
表示,父组件可以在这个占位符中填充任何模板代码,如 HTML、组件等,填充的内容会替换子组件的<slot></slot>
标签,父组件填充的内容称为插槽内容。
- 子组件不提供插槽时,父组件填充失效
- 父组件无填充时,
<slot></slot>
中的备用内容会启用生效 - 父级模板里的所有内容都是在父级作用域中编译的,子模板里的所有内容都是在子作用域中编译的,互不影响
二、匿名插槽(默认插槽)
介绍
在外部组件没有提供任何内容的情况下,可以使用匿名插槽提供默认内容。
使用场景
比如
MyComponent.vue
<n-el>
<slot>这是一个默认展示的内容</slot>
</n-el>
//组件使用
<MyComponent/>
如下:
如果外部组件提供了插槽内容,我们提供的内容会覆盖掉默认的内容
如下:
<MyComponent>加入一段文字</MyComponent>
注:
插槽内容可以是任意合法的模板内容,不局限于文本。
如下:
<MyComponent>
<n-button>加入一个按钮</n-button>
</MyComponent>
三、具名插槽
介绍
<slot>
元素带有 name 属性的插槽被称为具名插槽。
使用场景
作用于一个组件中拥有多个插槽,而name
相当于插槽的标识,用来给各个插槽分配唯一的 ID。
MyComponent.vue
<n-el class="flex flex-col justify-center items-center h-[80vh] w-full">
<n-el class="text-[pink] text-[18px] mb-2">组件相关内容</n-el>
<slot name="head"></slot>
<slot name="main"></slot>
<slot name="footer"></slot>
</n-el>
外部引用该组件
<MyComponent>
<template v-slot:head>
<n-el>这是头部内容</n-el>
</template>
<template v-slot:main>
<n-el>这是主体内容</n-el>
</template>
<template v-slot:footer>
<n-el>这是尾部内容</n-el>
</template>
<template v-slot:no>
<n-el>组件中没有可匹配的插槽name,不显示</n-el>
</template>
</MyComponent>
v-slot
可以简写成#
<MyComponent>
<template #head>
<n-el>这是头部内容</n-el>
</template>
<template #main>
<n-el>这是主体内容</n-el>
</template>
<template #footer>
<n-el>这是尾部内容</n-el>
</template>
<template #no>
<n-el>组件中没有可匹配的插槽name,不显示</n-el>
</template>
</MyComponent>
现在 <template>
元素中的所有内容都将被传递到相应的插槽。
注意:
匿名插槽也有自己的name
,只不过 name 会被隐式地命名为default
。
上面的写法等价于:
四、动态插槽名
<MyComponent>
<template v-slot:[slotName]>
...
</template>
<!-- 缩写为 -->
<template #[slotName]>
...
</template>
</MyComponent>
如下
MyComponent.vue
<n-el>
<n-el>组件相关内容</n-el>
<slot name="head"></slot>
</n-el>
<script setup lang="ts">
const data = 'head'
</script>
<template>
......
<MyComponent>
<template #[data]> 头部内容 </template>
</MyComponent>
.......
</template>
五、作用域插槽
介绍
作用域插槽可以让父级外层组件能够访问子组件的数据,子组件向将数据提供给插槽,组件 props 传递数据的方式,子组件向插槽传递一个attributes
,父组件通过v-slot
带的值(任意命名)来获取子组件的数据。
使用场景
(一)、默认插槽
MyComponent.vue
<n-el class="flex flex-col justify-center items-center h-[80vh] w-full">
<slot content="螺蛳粉" data="10"></slot>
</n-el>
写法一: v-slot 写在组件上
<MyComponent v-slot="res">
<n-el>老板:来 {{ res.data }} 份 {{ res.content }} ~</n-el>
</MyComponent>
注意:
v-slot="res"
可以类比这里的函数签名,和函数的参数类似,我们也可以在 v-slot
中使用解构:
<MyComponent v-slot="{ data, content }">
<n-el>
老板:来 {{ data }} 份 {{ content }} ~
</n-el>
</MyComponent>
写法二: v-slot 写在 template 上
<MyComponent>
<template v-slot:default="res">
<n-el>老板:来 {{ res.data }} 份 {{ res.content }} ~</n-el>
</template>
//或者
<template #default="res">
<n-el>老板:来 {{ res.data }} 份 {{ res.content }} ~</n-el>
</template>
</MyComponent>
(二)、具名插槽
具名作用域插槽的工作方式也是类似的,插槽 props 可以作为 v-slot
指令的值被访问到:v-slot:name="slotProps"
。当使用缩写时是这样:
MyComponent.vue
<n-el class="flex flex-col justify-center items-center h-[80vh] w-full">
<slot content="北京烤鸭" data="5" name="food1"></slot>
<slot content="长沙臭豆腐" data="15" name="food2"></slot>
</n-el>
<MyComponent>
<template #food1="res">
<n-el>老板:来 {{ res.data }} 份 {{ res.content }} ~</n-el>
</template>
<template #food2="res">
<n-el>老板:来 {{ res.data }} 份 {{ res.content }} ~</n-el>
</template>
</MyComponent>