一般来说,在Vue项目中使用父子组建时,都是把通用的HTML结构提取出来写成一个子组件,需要动态展示的数据用过prop属性传递,不过有时候我们可能想给子组件传递一个HTML代码,这个时候用prop不太适用,Vue给我们提供了slot(插槽)可以实现这种应用场景.下面是自己学习后总结的几种插槽使用方式
1. 普通使用方式
<template>
<!-- 如果有多个插槽,可以通过name命名 -->
<div style="background-color: yellowgreen">
<slot name="header"></slot>
<!-- 父组件传递过来的值会展示在slot标签中 -->
<slot></slot>
<ul v-
if
="todo">
<li>姓名: {{todo.name}}</li>
<li>年龄: {{todo.age}}</li>
<li>爱好: {{todo.hobby}}</li>
<div style="color: gold">
<slot name="footer"></slot>
</template>
<script>
export
default
{
name:
'child'
,
props: {
todo: Object
data () {
return
{
created () {
console.log(
this
.todo, 'todo'
)
</script>
//
父组件
<template>
<!-- 引入子组件 -->
<child :todo="list">
<!-- 这里的内容会渲染到子组件name为header的标签中 -->
<template slot="header">
<p>放在头部的内容</p>
</template>
<!-- 子组件双标签中的内容会被渲染到子组件的slot标签里 -->
<h3>插槽标题</h3>
<!-- 这里的内容会渲染到子组件name为footer的标签中 -->
<template slot="footer">
<p>放在底部的内容</p>
</template>
</child>
</template>
<script>
import child from
'./child'
export
default
{
name:
'parent'
,
components: {child},
data () {
return
{
list: {
name:
'灵梦'
,
age:
18
,
text:
'热爱学习'
,
hobby:
'踢足球'
</script>
渲染效果:
2. 作用域插槽
如果你希望从子组件获取数据,进行其他数据展示,这个时候你可以使用作用域插槽
<template>
<ul v-
if
="todo.length" v-
for
="item in todo" :key="item.id">
<li>姓名: {{item.name}}</li>
<li>年龄: {{item.age}}</li>
<li>爱好: {{item.hobby}}</li>
</template>
<script>
export
default
{
name:
'child'
,
props: {
todo: Array
</script>
//
父组件
<template>
<!-- 引入子组件 -->
<child :todo="list">
</child>
</template>
<script>
import child from
'./child'
export
default
{
name:
'parent'
,
components: {child},
data () {
return
{
list: [
{name:
'灵梦', age: 18, text: '热爱学习', hobby: '踢足球', id: 1
},
{name:
'李明', age: 13, text: '画画很棒', hobby: '画画', id: 2
},
{name:
'韩梅梅', age: 25, text: '性格文静', hobby: '做手工', id: 3
}
</script>
普通调用,渲染出来的数据就是这样,但是如果我们想在第二项渲染中把hobby改成text,这时候就需要子组件把数据传过来,父组件改变渲染方式了
<ul v-
if
="todo.length" v-
for
="(item,index) in todo" :key="item.id">
<li>姓名: {{item.name}}</li>
<li>年龄: {{item.age}}</li>
<!-- 如果是第二项,就使用作用域插槽,重新展示 -->
<li v-
if
="index === 1">
<!-- 定义了content把item传递到父组件,定义的名字可以随意取,需要传递的数据写在后面 -->
<slot :content="item"></slot>
<li v-
else
>爱好: {{item.hobby}}</li>
</template>
<script>
export
default
{
name:
'child'
,
props: {
todo: Array
</script>
//
父组件
<template>
<!-- 引入子组件 -->
<child :todo="list">
<!-- 在子组件用slot-scope结收传递过来的数据,接收的名字可以随意取 -->
<template slot-scope="scope">
<!-- scope后接的就是你在子组件定义的传递值的名称,scope.content就拿到了传递过来的值,在这里可以直接使用 -->
描述: {{scope.content.text}}
</template>
</child>
</template>
<script>
import child from
'./child'
export
default
{
name:
'parent'
,
components: {child},
data () {
return
{
list: [
{name:
'灵梦', age: 18, text: '热爱学习', hobby: '踢足球', id: 1
},
{name:
'李明', age: 13, text: '画画很棒', hobby: '画画', id: 2
},
{name:
'韩梅梅', age: 25, text: '性格文静', hobby: '做手工', id: 3
}
</script>
渲染出来的效果是这样,第二项李明的展示内容就改变了
在很多Vue的插件中也有使用作用域插槽的,比如element-ui的table组件,它就可以通过添加作用域插槽改变渲染的原始数据