内容插槽
插槽无默认内容
<template>
<div>
<child>
<h1>Hello World!</h1>
</child>
</div>
</template>
<script>
import Child from './child'
export default {
name: 'Parent',
components: {Child}
}
</script>
<style>
</style>
<template>
<div>
<header>
<slot></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot>
</slot>
</footer>
</div>
</template>
<script>
export default {
name: 'Child'
}
</script>
<style>
</style>
Hello World!
Hello World!
Hello World!
通过上面的例子可以看到,child子组件定义了多个插槽,但是都没给插槽设置name,也就是后面会说到的具名插槽,父组件使用子组件时设置的内容在每个插槽位置都会显示。因此默认插槽只能有一个,有多个的话需要使用具名插槽
部分插槽有默认内容
<template>
<div>
<child>
<h1>Hello World!</h1>
</child>
</div>
</template>
<script>
import Child from './child'
export default {
name: 'Parent',
components: {Child}
}
</script>
<style>
</style>
<template>
<div>
<header>
<slot name="header">学生管理系统</slot>
</header>
<main>
<slot>中间内容</slot>
</main>
<footer>
<slot name="footer">
xxxxxxx大学
</slot>
</footer>
</div>
</template>
<script>
export default {
name: 'Child'
}
</script>
<style>
</style>
学生管理系统
Hello World!
xxxxxxx大学
通过上面的例子可以看出,父组件使用时不指定插槽name的话即是默认插槽,且会覆盖默认插槽的默认内容。
具名插槽
<template>
<div>
<child>
<h1 slot="header">班级管理系统</h1>
<template #main>Hello World!</template>
<template v-slot:footer>
<h1>XXXXX班级</h1>
</template>
</child>
</div>
</template>
<script>
import Child from './child'
export default {
name: 'Parent',
components: {Child}
}
</script>
<style>
</style>
<template>
<div>
<header>
<slot name="header">学生管理系统</slot>
</header>
<main>
<slot name="main">中间内容</slot>
</main>
<footer>
<slot name="footer">
xxxxxxx大学
</slot>
</footer>
</div>
</template>
<script>
export default {
name: 'Child'
}
</script>
<style>
</style>
班级管理系统
Hello World!
XXXXX班级
上面有三种方式完成的具名插槽的实现,其中#main
和v-slot:"main"
是vue 2.6.0新增的。#main
是v-slot:"main"
的缩写形式
需要注意的是,v-slot
和. #
指令必须放在<template>
标签上,不然会报错。这是因为需要<template>
标签来用作渲染内容的容器。
作用域插槽
如果子组件中存在数据,那么这些数据也可以通过作用域插槽传递回父组件。这可以通过在插槽中使用一定的语法来实现。当子组件中的数据更新时,父组件将自动接收这些更新。
比如现在想实现一个展现三国人物刘关张的历史信息页面,但是关于刘关张的人物信息需要请求接口拿到任务的信息,同时展现人物的信息形式也是待定的。这时候就需要借助作用域插槽来实现子组件的数据传回父组件了。
子组件
<template>
<div>
<header v-if="$scopedSlots.header">
<h1>header</h1>
<ul>
<li
v-for="(item,index) in dataList"
:key="index"
>
<div>{{item.name}}</div>
<slot
:item="item"
name="header"
></slot>
</li>
</ul>
</header>
<main v-if="$scopedSlots.main">
<h1>main</h1>
<ul>
<li
v-for="(item,index) in dataList"
:key="index"
>
<div>{{item.name}}</div>
<slot
:item="item"
name="main"
></slot>
</li>
</ul>
</main>
<footer v-if="$scopedSlots.footer">
<h1>footer</h1>
<ul>
<li
v-for="(item,index) in dataList"
:key="index"
>
<div>{{item.name}}</div>
<slot
:item="item"
name="footer"
></slot>
</li>
</ul>
</footer>
</div>
</template>
<script>
export default {
name: 'Child',
props: {
dataList: Array
},
mounted() {
}
}
</script>
<style scoped>
ul li {
display: flex;
justify-content: space-between;
width: 200px;
}
</style>
父组件
<template>
<div>
<!-- 旧的用法 -->
<child :dataList="dataList">
<button
slot="header"
slot-scope="scope"
@click="show(scope.item)"
>
查看人物
</button>
</child>
<!-- v-slot用法 -->
<child :dataList="dataList">
<template v-slot:main="scope">
<button @click="show(scope.item)">
查看人物
</button>
</template>
</child>
<!-- v-slot的缩写用法 -->
<child :dataList="dataList">
<template #footer="{item1:item}">
<button @click="show(item)">
查看人物
</button>
</template>
</child>
<!-- 解构插槽props -->
<child :dataList="dataList">
<template #footer="{item}">
<button @click="show(item)">
查看人物
</button>
</template>
</child>
<!-- 解构插槽props同时更换别名 -->
<h1>#footer="scope" 形式</h1>
<child :dataList="dataList">
<template #footer="{item:itemm}">
<button @click="show(itemm)">
查看人物
</button>
</template>
</child>
<!-- 解构插槽props设置默认值 -->
<h1>#footer="scope" 形式</h1>
<child :dataList="dataList">
<template #footer="{newItem={name:'诸葛亮',value:'4'}}">
<button @click="show(newItem)">
查看人物
</button>
</template>
</child>
</div>
</template>
<script>
import Child from './child'
export default {
name: 'Parent',
components: {Child},
data() {
return {
dataList: [{name: '刘备', value: '1'}, {name: '关羽', value: '2'}, {name: '张飞', value: '3'}]
}
},
methods: {
show(item) {
console.log(item)
}
}
}
</script>
<style>
</style>
输出结果
header
刘备 查看人物
关羽 查看人物
张飞 查看人物
main
刘备 查看人物
关羽 查看人物
张飞 查看人物
footer
刘备 查看人物
关羽 查看人物
张飞 查看人物
footer
刘备 查看人物
关羽 查看人物
张飞 查看人物
footer
刘备 查看人物
关羽 查看人物
张飞 查看人物
footer
刘备 查看人物
关羽 查看人物
张飞 查看人物
这里需要注意下$slots
和$scopedSlots
的区别在于$scopedSlots
包含作用域插槽和具名插槽。而$slots
只包含具名插槽。
动态插槽
子组件
<template>
<div>
<header v-if="$scopedSlots.header">
<h1>header</h1>
<ul>
<li
v-for="(item,index) in dataList"
:key="index"
>
<div>{{item.name}}</div>
<slot
:item="item"
name="header"
></slot>
</li>
</ul>
</header>
<main v-if="$scopedSlots.main">
<h1>main</h1>
<ul>
<li
v-for="(item,index) in dataList"
:key="index"
>
<div>{{item.name}}</div>
<slot
:item="item"
name="main"
></slot>
</li>
</ul>
</main>
<footer v-if="$scopedSlots.footer">
<h1>footer</h1>
<ul>
<li
v-for="(item,index) in dataList"
:key="index"
>
<div>{{item.name}}</div>
<slot
:item="item"
name="footer"
></slot>
</li>
</ul>
</footer>
</div>
</template>
<script>
export default {
name: 'Child',
props: {
dataList: Array
},
mounted() {
}
}
</script>
<style scoped>
ul li {
display: flex;
justify-content: space-between;
width: 200px;
}
</style>
父组件
<template>
<div>
<!-- 动态插槽 -->
<child :dataList="dataList">
<template #[slotName]="{item}">
<button @click="show(item)">
查看人物
</button>
</template>
</child>
</div>
</template>
<script>
import Child from './child'
export default {
name: 'Parent',
components: {Child},
data() {
return {
dataList: [{name: '刘备', value: '1'}, {name: '关羽', value: '2'}, {name: '张飞', value: '3'}],
slotName: 'main'
}
},
methods: {
show(item) {
console.log(item)
}
}
}
</script>
<style>
</style>
main
刘备 查看人物
关羽 查看人物
张飞 查看人物
这篇文章写得深入浅出,让我这个小白也看懂了!
回复