slot具有“占坑”的作用,在子组件占好了位置,那父组件使用该子组件标签时,新添加的DOM元素就会自动填到这个坑里面。
slot又分三类,默认插槽,具名插槽和作用域插槽。
1、默认插槽(单个插槽,没有指定name)
又名匿名插槽,当slot没有指定name属性值的时候一个默认显示插槽,一个组件内只有一个匿名插槽。
注意:
- 如果有多个DOM元素,会一起插入到<slot></slot>这个标签内;
- 插槽可以提供一个默认内容,如果父组件没有为这个插槽提供内容,会显示默认的内容。如果父组件为这个插槽提供了内容,则默认的内容会被替换掉。<slot>defalut value</slot>。
例如: 给child组件添加slot插槽,那么父组件的添加的DOM元素就填充到这个slot插槽里面了。
因为插槽放在了子组件的最后,所以<span>我是魔鬼</span> 会插入到 <h1>我是子组件</h1>的后面。
<div id="app">
<children>
<span>我是魔鬼</span>
<!--上面这行会显示在 “我是子组件” 数据后面-->
</children>
</div>
<script>
var vm = new Vue({
el: '#app',
components: {
children: {
template: "<h1>我是子组件</h1><slot></slot>"
}
}
});
</script>
2、具名插槽(添加了name属性)
为插槽添加了name属性,可以添加多个聚名插槽
当我们需要将父组件添加的HTML标签 放在子组件里的不同位置。使用具名插槽实现:
- 先在子组件的slot标签里,分别添加name=”name名” 属性:<slot name="header"></slot>
- 其次父组件在要分发的标签里添加 slot=”name名” 属性,然后就会将对应的标签放在对应的位置了:<span slot="header">我是header</span>
简单理解就是:给子组件占的每一个坑取名,将父组件添加的HTML元素添加到指定名字的坑,就实现了分发内容在不同位置显示。
【Child组件模板】:<slot name="header"></slot>
<template>
<div>
<slot name="header"></slot>
<h1>我是子组件</h1>
<slot name="footer"></slot>
</div>
</template>
【父组件引用Child组件】:<span slot="header">我是header</span>
<Child>
<span slot="header">我是header</span>
<span slot="footer">我是footer</span>
</Child>
3、作用域插槽
- 有的时候你希望提供的组件带有一个可从子组件获取数据的可复用的插槽
- 作用域插槽的关键之处就在于,父组件能接收来自子组件的slot传递过来的参数
- 作用域插槽必须放在template里面(父组件中)
- template标签中的属性slot-scope="props"声明从子组件传递的数据都放一个自定义属性内。
例:
<div id="root">
<child>
<!--1.作用域插槽必须必须放在template标签内--->
<!--2.slot-scope="props"声明从子组件传递的数据都放在props里-->
<template slot-scope="props">
<li>{{props.value}}</li>
</template>
</child>
</div>
<script>
Vue.component('child',{
data: function(){
return {
list:[1,2,3,4]
}
},
template: `<div>
<ul>
<!--我们为list中的每个元素准备了一个插槽,将value对象作为一个插槽的prop传入-->
<slot v-for="value in list" :value=value>//使用slot占位
</slot>
</ul>
</div>`
})
var vm=new Vue({
el: '#root'
})
</script>
4、插槽实现原理:
当子组件vm实例化时,获取到父组件传入slot标签的内容,存放在vm.$slot
中,默认插槽为vm.$slot.default
,具名插槽为vm.$slot.xxx
,xxx 为插槽名,当组件执行渲染函数时候,遇到slot标签,使用$slot(
父组件传入slot标签的内容)
中的内容进行替换,此时可以为插槽传递数据,若存在数据,则可称该插槽为作用域插槽。