这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战
缘由
vue的插槽用过,但是不是很常用,因为有别的方案也能实现,比如通过props传值然后通过v-if或者v-show来控制显隐。但是有时候需要自定义的内容很多,props传的值过多,这时候插槽就可以派上用场。所以今天总结下vue的插槽知识,来学学吧。
定义
vue的插槽是在调用组件的时候用的,组件内定义一个默认内容(可选),如果调用的时候传入自定义内容,则会使用自定义内容进行渲染,否则会使用默认内容渲染。
子组件必须要有slot标签,如果没有slot标签,则无法渲染父组件的自定义内容。
例子:
<div id="app">
<user-info>
<h3>我是自定义内容</h3>
</user-info>
</div>
<script>
Vue.component('user-info', {
template: '<div><slot>我是备用内容</slot></div>'
})
const vm = new Vue({
el: '#app'
})
</script>
结果如下:
传了自定义内容:
没传自定义内容:
具名插槽
如果想把插槽渲染在特定的结构中,那么vue是支持具名插槽,例子如下:
<div id="app">
<user-info>
<h3 slot="header">我是头部内容</h3>
<h3>我是content</h3>
<h3 slot="footer">我是底部内容</h3>
</user-info>
</div>
<script>
Vue.component('user-info', {
template: `
<div>
<slot name="header"></slot>
<slot></slot>
<slot name="footer"></slot>
</div>`
})
const vm = new Vue({
el: '#app'
})
</script>
具名插槽是通过父组件标签的slot属性值和子组件的slot标签的name值匹配,符合的展示父组件的具名插槽,不符合就默认展示slot标签内的内容。
父组件标签没有slot属性值都当作默认默认插槽,替换默认的slot标签的内容。
slot-scope
如果你想在父组件的插槽使用子组件上的数据,可以使用slot-scope。
<div id="app">
<user-info>
<!-- 通过{}解构 -->
<h3 slot-scope="{info}">{{info}}</h3>
</user-info>
</div>
<script>
Vue.component('user-info', {
data() {
return {
info: { name: '答案cp3' }
}
},
template: `
<div>
<slot :info="info"></slot>
</div>`
})
const vm = new Vue({
el: '#app'
})
</script>
新语法
vue自2.6.0及以上版本改进了具名插槽和slot-scope的写法,下面也总结一下。
上面的具名插槽和slot-scope的写法官方已经不推荐使用,大家后面还是以新语法为主。
具名插槽
使用v-slot:name来表示, 而且v-slot只能用在template标签上(但是如果你只有默认插槽,v-slot可以使用在组件上)。默认插槽是v-slot:default,可以简写v-slot。
注意:v-slot内部标签不能再使用着v-slot
改写上面的例子:
<div id="app">
<user-info>
<!-- `v-slot`一般只能用在template标签 -->
<template v-slot:header>
<h3 >我是头部内容</h3>
</template>
<template v-slot:default>
<h3>我是content</h3>
</template>
<template v-slot:footer>
<h3 >我是底部内容</h3>
</template>
</user-info>
</div>
<script>
Vue.component('user-info', {
template: `
<div>
<slot name="header"></slot>
<slot></slot>
<slot name="footer"></slot>
</div>`
})
const vm = new Vue({
el: '#app'
})
</script>
slot-scope
改写上面的slot-scope例子
<div id="app">
<user-info>
<!-- 通过{}解构 -->
<!-- `v-slot`一般只能用在template标签 -->
<!-- 等同于v-slot:default -->
<template v-slot="{info}">
<h3>{{info}}</h3>
</template>
</user-info>
</div>
<script>
Vue.component('user-info', {
data() {
return {
info: { name: '答案cp3' }
}
},
template: `
<div>
<slot :info="info"></slot>
</div>`
})
const vm = new Vue({
el: '#app'
})
</script>
v-slot缩写
v-slot的缩写是#,它后面必须带有name,比如默认插槽,#default, 不能缩写#。
<user-info>
<!-- 等同于v-slot:header -->
<template #header>
<h3 >我是头部内容</h3>
</template>
<!-- 等同于v-slot:default -->
<template #default>
<h3>我是content</h3>
</template>
<!-- 等同于v-slot:footer -->
<template #footer>
<h3 >我是底部内容</h3>
</template>
</user-info>