最开始接触或者注意这个东西,是在用elementUI做后台管理系统时,对列表组件中某些特定的列做修改或判断时会用到。在template中有个slot-scope="scope",当时只是知道怎么用,知其然不知其所以然。
<el-table v-loading="loading" :data="tableList">
<el-table-column prop="name" label="名称" />
<el-table-column prop="status" label="状态">
<template slot-scope="scope">
<span v-if="scope.row.status===0">未完成</span>
<span v-if="scope.row.status===1">已完成</span>
<span v-if="scope.row.status===2">已启用</span>
</template>
</el-table-column>
</el-table>
回头仔细研究了一番,总结就一句话:在vue的模块化设计中,为子组件进行赋能。为何这样说:
聚个例子,我们现在封装了一个移动端列表的行展示组件zd-item,其样式和功能覆盖了大部分的需求,但是对一些特殊的行,我们要进行样式的调整和功能的修改,显然为这一个特殊的行通过props传值的方式修改样式或$emit的方式多加一个事件也是不值得,重新封装一个类似组件更是没必要的,这个时候我们就需要为我们的行组件赋能,让其支持在父组件中使用时可以自定义内容及样式和事件。
首先我们来定义子组件
<template>
<div class="child">
<!--slot起到一个占位的作用 在父组件中引用时可修改同位置的内容-->
<!--slot的两外一个作用 将子组件的值传给父组件 让其使用-->
<slot :childName="'子组件修改后的'+childItem.name">{{childItem.name}}</slot>
<button @click="clickChild">点击子组件</button>
</div>
</template>
<script>
export default {
name: "child",
props: {
childItem: {
type: Object,
default: {},
},
},
methods: {
clickChild() {
console.log('我是子的方法')
},
},
}
</script>
<style scoped>
.child{
display: flex;
justify-content: space-between;
}
</style>
然后在父组件中使用子组件
<template>
<div>
<child :key="index" v-for="(item,index) in list" :childItem="item">
<!--因为子组件使用了slot占位 所以在这里可以用template修改子组件同位置的内容-->
<!--由于子组件中通过:childName传递了值 所以这里能通过aaa.childName获取值-->
<template slot-scope="aaa">
<span v-if="item.id===3" style="color: red;">{{aaa.childName}}</span>
</template>
</child>
</div>
</template>
<script>
import child from './child'
export default {
name: "father",
components:{
child,
},
data(){
return{
list:[
{id:1,name:'张三'},
{id:2,name:'李四'},
{id:3,name:'王五'},
]
}
},
}
</script>
插槽分为三种:匿名插槽、具名插槽、作用域插槽。
上面提到的时作用域插槽,其核心作用时占位和传值。
接下来我们看看另外两种插槽:匿名插槽和具名插槽
<!-- 子组件 -->
<template>
<div class="child">
<slot><!-- 我是子组件提供的空占位符 可以在这里插入值 --></slot>
<slot>我是子组件提供的默认值 可修改我</slot>
</div>
</template>
<!-- 父组件 -->
<template>
<div class="father">
<child>
<span>你提供了占位符 那我就选择性的 给你插个值吧</span>
<span>你有默认值 但用的slot占位符 我就可以修改你</span>
</child>
</div>
</template>
像上面这种只是提供了占位符,不牵扯数据传递的slot方式,我们就称其为匿名插槽,也可以叫单个插槽或者默认插槽。与之相对的,是具名插槽。具名插槽的使用场景是什么呢?
以上面代码为案例,我们在父组中只想修改值而不想插入值,但是当在父组件中template里设置单个值时并不能达到修改的目的,因为没有任何标识,子组件默认就会指到第一个slot的位置,这是我们就用到了具名插槽,给支持修改的slot加个name="center",然后在父组件中用v-slot:center指向要修改的位置。
<!-- 子组件 -->
<template>
<div class="child">
<slot><!-- 我是子组件提供的空占位符 可以在这里插入值 --></slot>
<slot name="center">我是子组件提供的默认值 可修改我</slot>
</div>
</template>
<!-- 父组件 -->
<template>
<div class="father">
<child>
<template v-slot:center>
<span>我用v-slot具名插槽指向了子组件中的center位置</span>
</template>
</child>
</div>
</template>