vue中的插槽是为了方便父组件调用子组件时,往子组件中传入一些自定义的代码片段或内容。
根据插槽的类型、作用, vue中的插槽基本分为三种:默认插槽,具名插槽和 作用域插槽
默认插槽就是在子组件中,未命名的插槽。这类插槽,在使用时,子组件中使用 标签定义,在父组件中,会将调用子组件标签内的非 标签内容全部 插入默认插槽。而且在子组件中还可以自定义父组件未传值的显示内容。
代码示例如下:
son.vue 组件中
<template>
<button type="submit">
<slot>
这是son组件中默认显示的内容
slot>
button>
template>
parent.vue 组件中 引用 son 组件
<script setup>
import SubmitButton from './SubmitButton.vue'
script>
<template>
<SubmitButton />
<br/>
<SubmitButton>
<template>
我是template标签中的内容
template>
我是template标签外的内容
SubmitButton>
template>
最后的显示效果为
具名插槽是在子组件中 使用name属性给 命名了的插槽,它主要用于按照一定的顺序,给子组件指定位置插入内容。如自定义一个页面的组件,在组件中定义好头部,内容,尾部几块地方,在引用这个组件的时候,就可以使用具名插槽给指定的地方插入内容。
为区分父组件调用的子组件的 那一个具名插槽,通常在父组件中用 插入内容 的方式引用,v-slot的语法糖为# ,因此可以写为 插入内容
代码示例如下:
son.vue 组件中
<template>
<div class="container">
<header>
<slot name="header">slot>
header>
<main>
<slot>slot>
main>
<footer>
<slot name="footer">slot>
footer>
div>
template>
<style>
footer {
border-top: 1px solid #ccc;
color: #666;
font-size: 0.8em;
}
style>
parent.vue 组件中 引用 son 组件
<script setup>
import BaseLayout from './BaseLayout.vue'
script>
<template>
<BaseLayout>
<template #header>
<h1>Here might be a page titleh1>
template>
<template #default>
<p>A paragraph for the main content.p>
<p>And another one.p>
template>
<template #footer>
<p>Here's some contact infop>
template>
BaseLayout>
template>
内容显示如下
在子组件中,如果同时存在有具名插槽和默认插槽,默认插槽在父组件中可以通过 <script setup>
import BaseLayout from './BaseLayout.vue'
script>
<template>
<BaseLayout>
<template #header>
<h1>Here might be a page titleh1>
template>
<p>A paragraph for the main content.p>
<p>And another one.p>
<template #footer>
<p>Here's some contact infop>
template>
BaseLayout>
template>
作用域插槽,我个人理解,按其作用可以取名为 【子组件传值插槽】,它是三个插槽中最复杂的。因为它有一个很重要的作用就是可以把子组件的值重新传递到父组件,然后由父组件取到,判断渲染。 你可能会想,什么情况会需要这种用法,我们不是直接把数据传给子组件,让它在自己内部做逻辑处理就可以了吗。大部分情况下的确如此,但是有时,我们可能需要在父组件中调用子组件后,在父组件内对子组件渲染出来的数据做一些逻辑判断,如什么时候显示隐藏等。这时,子组件能把数据传递回来就很重要了。 代码示例如下: son.vue 组件中 parent.vue 组件中 引用 son 组件 上文显示内容为 当然比较复杂一点的用法,作用域插槽,具名插槽,默认插槽也可以混合使用,比如下面 代码示例如下: son.vue 组件中 parent.vue 组件中 引用 son 组件 关于作用域插槽你可能还有几个疑问,这里我也在网上找到了一些答案来解答: 疑问1:一般不是我们传参数来调用组件吗?为什么组件还把数据传递回来? 疑问2: 既然子组件最终还要把我给他的数据,再返还给我,那我当初还干嘛给它,能不能就自己在父组件里玩? 疑问3: 父组件需要子组件的数据?那不会有$emit和vuex嘛,为什么要有slot-scope? 本文主要总结了vue中三种主要插槽的使用了和注意点,其中最为复杂的为作用域插槽,它的主要作用是用来方便子组件给父组件进行值传递,方便父组件拿到子组件的一些值,做渲染判断 更多用法和介绍可以参见:vue官网-插槽的使用三 作用域插槽
<script>
export default {
data() {
return {
greetingMessage: 'hello'
}
}
}
script>
<template>
<div>
<slot :text="greetingMessage" :count="1">slot>
div>
template>
<script>
import MyComponent from './MyComponent.vue'
export default {
components: {
MyComponent
}
}
script>
<template>
<MyComponent v-slot="slotProps">
{{ slotProps.text }} {{ slotProps.count }}
MyComponent>
template>
v-slot="slotProps"
可以类比这里的函数签名,和函数的参数类似,我们也可以在 v-slot
中使用解构,上面父组件中也可以写为<MyComponent v-slot="{ text, count }">
{{ text }} {{ count }}
MyComponent>
hello 1
<template>
<div class="container">
<header>
<slot name="header" :headerProps="具名插槽01">slot>
header>
<main>
<slot :defaultProps="默认插槽">slot>
main>
<footer>
<slot name="footer" :footer="具名插槽02">slot>
footer>
div>
template>
<style>
footer {
border-top: 1px solid #ccc;
color: #666;
font-size: 0.8em;
}
style>
<script>
import MyComponent from './MyComponent.vue'
export default {
components: {
MyComponent
}
}
script>
<template>
<MyComponent>
<template #header="headerProps">
{{ headerProps }}
template>
<template #default="defaultProps">
{{ defaultProps }}
template>
<template #footer="footerProps">
{{ footerProps }}
template>
MyComponent>
template>
的确,调用ui组件时一般是我们传递配置参数给他们。
但是就像elemnt-ui的table组件,你把数组传递给table后,是不是有时候需要拿到某一行的row对象
并根据row对象里的字段,来判断一些内容的显示隐藏?
因为循环的过程发生在table组件内部,所以table组件可以方便的获取到每一项数据,但是这些数据最终不是给组件的,而是我们自己要用的业务数据。所以也需要一个方式,让调用者能拿到自己想要的数据
如果你不把数据给子组件当然可以。但是就等于抛弃掉了子组件的封装,只能你直接在父组件自己写一个列表
毕竟你不把数据给子组件,子组件还渲染个锤子?没有父子关系的话,也就不用什么插槽了。
但是咱不是为了封装后,可以复用嘛,总不能永远不用组件嘛
$emit和vuex是数据传递的一种方法,但是你可以尝试用$emit和vuex把todo传递给父组件。
你会发现的确没有合适的钩子、时机来$emit数据
总结