引言
对于插槽的概念,这里就不做赘述。在说作用域插槽之前,有必要说一下具名插槽,二者有相关性。
父组件通过prop
向子组件传递数据,通过插槽向子组件传递内容。前者传递的是组件的属性,后者传递的是vNode
节点。
具名插槽的前世(已废弃)
【1】在父组件调用子组件的开始标签和结束标签中添加任意DOM
代码或者template
块,给template
块或者任意标签添加slot='插槽名'
【2】在子组件中添加<slot name='插槽名'></slot>
parent.vue
<template>
<div>
<old-child>
<template slot='header'>
<div>
<p>这是template中的内容,也是一个具名插槽</p>
<div>这是template中的内容</div>
</div>
</template>
<div slot="footer">这是一个普通的标签,也是一个具名插槽</div>
<div>这只是一个标签</div>
</old-child>
</div>
</template>
<script>
import OldChild from './oldChild'
export default {
name: 'newParent',
components: {
OldChild
}
}
</script>
<style scoped>
</style>
child.vue
<template>
<div>
<slot name='header'></slot>
<slot></slot>
<slot name='footer'></slot>
</div>
</template>
<script>
export default {
name: 'oldChild'
}
</script>
<style scoped>
</style>
效果图:
具名插槽的今生
【1】在父组件调用子组件的开始标签和结束标签中添加template
块或任意DOM
,给具名插槽的DOM
使用template
包裹,给具名插槽的template
标签添加v-slot:插槽名
【2】在子组件中添加<slot name='插槽名'></slot>
v-slot
只能添加在template
标签上
parent.vue
<template xmlns:v-slot="http://www.w3.org/1999/XSL/Transform">
<div>
<slot-child>
<template v-slot:header>
<ul>
<li>新具名插槽</li>
</ul>
</template>
<!-- <div slot-scope='dataArr'>旧slot-scope,这是一个默认的插槽{{dataArr}}</div>-->
<div>这是一个默认的插槽的内容</div>
<template v-slot:footer>
<p>新具名插槽,这是一个底部</p>
</template>
</slot-child>
</div>
</template>
<script>
import SlotChild from './slotChild'
export default {
name: 'slotParent',
components: {
SlotChild
}
}
</script>
<style scoped>
</style>
child.vue
<template>
<div>
<slot name='header'></slot>
<slot name='footer'></slot>
<slot></slot>
</div>
</template>
<script>
export default {
name: 'slotChild',
data: function () {
return {
dataArr: [{
id: 1
},
{
id: 2
}],
user: 'Ross'
}
}
}
</script>
<style scoped>
</style>
效果如图:
作用域插槽的前世(已废弃)
【1】在父组件调用子组件的开始标签和结束标签中添加任意DOM
代码或者template
块,给template
块或者任意标签添加slot-scope="slotProps"
【2】在子组件中通过v-bind:变量名='子组件数据'
将子组件中的数据通过插槽传递给父元素
parent.vue
<template>
<div>
<old-child>
<div slot='nav' slot-scope='slotscopes'>{{slotscopes}}</div>
<template slot='header' slot-scope='slotscopes'>
<div>
{{slotscopes}}
</div>
</template>
<div slot="footer" slot-scope='slotscopes'>{{slotscopes}}</div>
<div slot-scope='slotscopes'>{{slotscopes}}</div>
</old-child>
</div>
</template>
<script>
import OldChild from './oldChild'
export default {
name: 'newParent',
components: {
OldChild
}
}
</script>
<style scoped>
</style>
child.vue
<template>
<div>
<slot name='nav' v-bind:dataArr='dataArr'></slot>
<slot name='header' v-bind="dataArr"></slot>
<slot v-bind="userName"></slot>
<slot name='footer' v-bind:userName="userName"></slot>
</div>
</template>
<script>
export default {
name: 'oldChild',
data: function () {
return {
dataArr: [{
id: '1',
name: 'lili'
},
{
id: '2',
name: 'jack'
}
],
userName: 'jjjj'
}
}
}
</script>
<style scoped>
</style>
效果图:
通过效果图可以看出,子元素未绑定变量时,会对数据进行遍历,所以通过子组件向父组件传递数据,应该绑定变量。
关于子元素未绑定变量时,为什么会对数据进行遍历的问题,同事去看了源码,帮解决了这个疑问(我,弱小),源码如下:
if (process.env.NODE_ENV !== 'production' && !isObject(bindObject)) {
warn(
'slot v-bind without argument expects an Object',
this
);
}
slot
上的v-bind
如果没有参数,应该传入一个对象,而不是一个数组。
注意:①子组件向父组件传递数据应该绑定变量;②slot和slot-scope已废弃
作用域插槽的今生
【1】在父组件调用子组件的开始标签和结束标签中添加template
块或任意DOM
,给具名插槽的DOM
使用template
包裹,给具名插槽的template
添加v-slot:插槽名
【2】在子组件中通过v-bind:变量名='子组件数据'
将子组件中的数据通过插槽传递给父元素
【3】如果数据要传递给具名插槽,在具名插槽的template
标签上修改v-slot:插槽名
为v-slot:插槽名='slotProps'
【4】如果数据要传递给默认插槽,将默认插槽的DOM
使用template
包裹,在template
标签上添加v-slot='slotProps'
,因为v-slot
只能在template
标签上使用
parent.vue
<template xmlns:v-slot="http://www.w3.org/1999/XSL/Transform">
<div>
<slot-child>
<template v-slot:header='dataArr'>
<ul>
<li>新具名插槽{{dataArr}}</li>
</ul>
</template>
<!-- <div slot-scope='dataArr'>旧slot-scope,这是一个默认的插槽{{dataArr}}</div>-->
<template v-slot='dataArr'>给默认插槽传递数据,这是一个默认的插槽{{dataArr}}</template>
<template v-slot:footer="slotProps">
<p>新具名插槽,这是一个底部{{slotProps}}</p>
</template>
</slot-child>
</div>
</template>
<script>
import SlotChild from './slotChild'
export default {
name: 'slotParent',
components: {
SlotChild
}
}
</script>
<style scoped>
</style>
child.vue
<template>
<div>
<slot name='header' v-bind:arr='dataArr'></slot>
<slot name='footer' :myUser="user"></slot>
<slot v-bind:arr='dataArr'></slot>
</div>
</template>
<script>
export default {
name: 'slotChild',
data: function () {
return {
dataArr: [{
id: 1
},
{
id: 2
}],
user: 'Ross'
}
}
}
</script>
效果如下: