插槽就是子组件中的提供给父组件使用的一个占位符,用 表示,父组件可以在这个占位符中填充任何模板代码,如 HTML、组件等,填充的内容会替换子组件的标签。
1.插槽基本使用
子组件SlotComponent.vue
<template>
<div class="child-box">
<p>我是子组件</p>
<!-- 插槽 -->
<slot></slot>
</div>
</template>
<script setup lang="ts">
</script>
父组件
<template>
<div class="demo1">
<h1>我是父组建</h1>
<SlotComponent></SlotComponent>
</div>
</template>
<script setup lang="ts">
import SlotComponent from "./component/SlotComponent.vue";
</script>
输出结果:
2.插槽默认内容
<template>
<div class="child-box">
<p>我是子组件</p>
<!-- 插槽 -->
<slot>
<p>我是默认内容</p>
</slot>
</div>
</template>
<script setup lang="ts"></script>
输出结果:
3.具名插槽
子组件SlotComponent.vue
<template>
<div class="child-box">
<p>我是子组件</p>
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
<script setup lang="ts"></script>
上段代码中我们添加了 3 个 slot 插槽,并且给其中两个 slot 标签添加了一个 name 属性,也就是每个插槽的名字。需要注意的是,上段代码中有一个插槽我们没有添加 name 属性,这个时候 Vue 会隐式的将这个插槽命名为“default”,
父组件
<template>
<div class="demo1">
<h1>我是父组建</h1>
<SlotComponent>
<template #header>
<div>我是 header{{ message }}</div>
</template>
<template #default>
<div>我没有名字{{ message }}</div>
<div>我没有名字{{ message }}</div>
<div>我没有名字{{ message }}</div>
</template>
<template #footer>
<div>我是 footer{{ message }}</div>
</template>
</SlotComponent>
</div>
</template>
<script setup lang="ts">
import SlotComponent from "./component/SlotComponent.vue";
const message = ref("---我是父组建中的数据");
</script>
输出结果:
4.简写
原写法
<template v-slot:footer></template>
简写
<template #footer></template>
默认插槽与具名插槽混用
当一个子组件中既有具名插槽,又有默认插槽时,该如何渲染呢?
前面我们说默认插槽会被隐式的命名为 default,所以我们传入内容时可以将插槽名字改为 defalut 即可。
子组件SlotComponent.vue
<template>
<div class="child-box">
<p>我是子组件</p>
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
<script setup lang="ts"></script>
父组件
<template>
<div class="demo1">
<h1>我是父组建</h1>
<SlotComponent>
<template #header>
<div>我是 header{{ message }}</div>
</template>
<template #default>
<div>我没有名字{{ message }}</div>
<div>我没有名字{{ message }}</div>
<div>我没有名字{{ message }}</div>
</template>
<template #footer>
<div>我是 footer{{ message }}</div>
</template>
</SlotComponent>
</div>
</template>
<script setup lang="ts">
import SlotComponent from "./component/SlotComponent.vue";
const message = ref("---我是父组建中的数据");
</script>
输出结果:
5.插槽作用域问题
上段代码中 message 是我们在父组件中定义的数据,但是在我们的子组件SlotComponent 中渲染了出来,说明子组件中的插槽是可以访问到父组件中的数据作用域的,但是反过来是不行的,因为我们无法通过插槽拿到子组件的数据。
- 总结:
插槽内容可以访问到父组件的数据作用域,就好比上述中的 message 是父组件的。
插槽内容无法访问到子组件的数据,就好比上述 App.vue 中的插槽内容拿不到子组件 child 的数据。
6.作用域插槽
前一节我们说父组件中的插槽内容是无法访问到子组件中的数据的,但是,万一我们有需求就是需要在插槽内容中获取子组件数据怎么办呢?
6.1默认插槽作用域传值
子组件SlotComponent.vue
<template>
<div class="child-box">
<p>我是子组件</p>
<slot text="我是子组件" :count="1"></slot>
</div>
</template>
<script setup lang="ts"></script>
父组件
<template>
<div class="demo1">
<h1>我是父组建</h1>
<SlotComponent v-slot="slotProps">
<div>{{ slotProps.text }}---{{ slotProps.count }}</div>
</SlotComponent>
</div>
</template>
<script setup lang="ts">
import SlotComponent from "./component/SlotComponent.vue";
</script>
输出结果:
上段代码中我们在子组件中 slot 标签上添加了一些自定义属性,属性值就是我们想要传递给父组件的一些内容。在父组件 中通过 v-slot="slotProps"等形式接收子组件传过来的数据,slotProps 的名字是可以任意取的,它是一个对象,包含了所有传递过来的数据。
需要注意的是,子组件传递过来的数据只能在子组件这个标签内使用。
父组件解构写法:
<template>
<div class="demo1">
<h1>我是父组建</h1>
<SlotComponent v-slot="{ text, count }">
<div>{{ text }}---{{ count }}</div>
</SlotComponent>
</div>
</template>
<script setup lang="ts">
import SlotComponent from "./component/SlotComponent.vue";
</script>
6.2具名插槽作用域传值
子组件SlotComponent.vue
<template>
<div class="child-box">
<p>我是子组件</p>
<slot name="header" text="我是子组件的" :count="1"></slot>
</div>
</template>
<script setup lang="ts"></script>
父组件
<template>
<div class="demo1">
<h1>我是父组建</h1>
<SlotComponent>
<template #header="{ text, count }">
<div>{{ text }}---{{ count }}</div>
</template>
</SlotComponent>
</div>
</template>
<script setup lang="ts">
import SlotComponent from "./component/SlotComponent.vue";
</script>
上段代码中我们给 slot 添加了一个 name,在父组件中接收数据的时候不在采用 v-slot=““形式了,而是直接再插槽内容上采用#header=”“形式,当时这是简写形式,你也可以写为:v-slot:header=””
6.tsx中插槽的使用
子组件
<script lang="tsx">
import { defineComponent} from 'vue';
export default defineComponent({
setup(props, context) {
const {slots}=context
return () => (
<div>默认插槽: {slots.default && slots.default()}</div>
);
},
});
</script>
<style scoped></style>
父组建写法一
<script lang="tsx">
import { defineComponent } from 'vue';
import Child from './component/child.vue'
export default defineComponent({
setup() {
const text = ref("欢迎");
return () => (
<div style="color: red" class="my-test">
<h1 v-text={text.value}></h1>
<p>333</p>
<Child v-slots={{
default: () => '默认的内容是'
}}/>
</div>
);
},
});
</script>
<style scoped></style>
父组建写法二
<script lang="tsx">
import { defineComponent } from 'vue';
import Child from './component/child.vue'
export default defineComponent({
setup() {
const text = ref("欢迎");
return () => (
<div style="color: red" class="my-test">
<h1 v-text={text.value}></h1>
<p>333</p>
<Child>
{{
default: () => '默认的内容是'
}}
</Child>
</div>
);
},
});
</script>
<style scoped></style>
输出结果:
7.插槽高阶用法
- 实际开发中可以遇到组件层层嵌套,如果遇到一下情况如何解决。
7.1. 如果父组件需要拿到子组件的数据
7.2. 父组件还需要拿到孙组件的数据
父组件 useSlot.vue
<template>
<div class="demo1">
<h1>我是父组建</h1>
<SlotComponent>
<template #action="data">
<div>我是 action----{{ data.text }}</div>
</template>
<template #SlotDemo="data">
<div>我是 SlotDemo----{{ data.obj.text }}</div>
</template>
</SlotComponent>
</div>
</template>
<script setup lang="ts">
import SlotComponent from "./component/SlotComponent.vue";
</script>
注释:
-
#action="data"
中的data为子组件
中传递过来的数据 -
#SlotDemo="data"
中的data为孙组件
中传递过来的数据
子组件 SlotComponent.vue
<script lang="tsx">
import SlotDemo from "./SlotDemo.vue";
import { Slots } from 'vue'
export default defineComponent({
name:'SlotComponent',
setup(props,{ attrs,slots,emit,expose }){
let state=reactive({ text:'我是子组件中的数据' })
//slots收到的插槽集合
//slot 当前插槽的名字 默认是default
//data 要传给插槽的数据
const getSlot = (slots: Slots, slot = 'default', data?: Recordable) => {
const slotFn = slots[slot] //获取到父组件SlotDemo插槽
if (!slotFn) return null //如果没在父组件找到插槽 就return null
return slotFn(data)// 将数据data传递给父组件中的插槽
}
return () =>(
<>
<div>{slots.action?.(state)}</div>
<SlotDemo>
{{
default: (data) => getSlot(slots,'SlotDemo',data),
}}
</SlotDemo>
</>
)
}
})
</script>
注释:
-
default: (data) => getSlot(slots,'SlotDemo',data),
:default代表SlotDemo
组件中的默认插槽data
表示SlotDemo
组件上v-bind绑定的参数, -
getSlot(slots,'SlotDemo',data)
:在slots中找到插槽SlotDemo,将参数data传给插槽SlotDemo,并返回插槽SlotDemo中的内容。
孙组件 SlotDemo.vue
<template>
<div class="SlotDemo">
<slot :obj="obj"></slot>
</div>
</template>
<script>
export default defineComponent({
setup() {
let obj=reactive({ text:'我是孙子组件' })
return { obj }
},
})
</script>
注释:文章来源:https://www.toymoban.com/news/detail-419543.html
-
:obj="obj"
表示要传给父组件的数据
输出结果:
文章来源地址https://www.toymoban.com/news/detail-419543.html
到了这里,关于vue3插槽的使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!