官网有说明作用域插槽的使用方法,对照例子写了下,跑是跑成功了,但是还是有点不知道这东西存在的意义,父组件操作子组件数据,直接$emit
不就行了,于是搜到了这个大神的文章,恍然大悟!作用域插槽使用场景就是有三个及以上层级的组件时,想要处理底层组件的数据,如果要分离业务设计,肯定是希望最高层级的父组件去处理,那就有跨层级处理的问题了,这个时候如果都使用$emit
处理,那么中间层的组件就耦合了业务,这个时候就可以考虑使用作用域插槽
四层级组件举例
组件关系如图:
总共有四层关系,第一层想要操作第四层的组件数据。
这个时候代码可以这样写(如下伪代码),中心思想是把需要操纵数据的子组件一层层暴露给最顶层的父组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="../../js/vue.js"></script>
<div id="app">
<comp-2-level :comp-2-level-data="parentData">
<template slot-scope="comp2SlotScope">
<comp-3-level :comp-3-level-data="comp2SlotScope.comp2Row">
<template slot-scope="comp3SlotScope">
<comp-4-level :comp-4-level-data="comp3SlotScope.row" @parent-click="itemClick"></comp-4-level>
</template>
</comp-3-level>
</template>
</comp-2-level>
</div>
<template id="comp2Level">
<div>
<div class="row">
<slot :comp2Row="comp2LevelData"></slot>
</div>
<div class="row">
<!--其他信息 -->
</div>
</div>
</template>
<template id="comp3Level">
<div>
<div>
<!--这里正常情况是要写comp4Level的组件引用的,但是因为要做操comp4Level的数据,所以这里写了一个作用域插槽,你也可以
在这插槽里面写上默认的代码,组件被使用的时候就有默认功能-->
<slot :row="comp3LevelData"></slot>
</div>
</div>
</template>
<template id="comp4Level">
<div>
<!--此处省略一万行代码.....-->
<a @click="comp4levelMeth(comp4LevelData)">{{comp4LevelData}}</a>
</div>
</template>
<script>
const comp2Level= {
template: '#comp2Level',
props: {comp2LevelData:Object}
}
const comp3Level={
template: '#comp3Level',
props:{comp3LevelData: Object}
}
const comp4Level = {
template: '#comp4Level',
props:{comp4LevelData: Object},
methods: {
comp4levelMeth(data){
this.$emit('parent-click', data)
}
}
}
const app = new Vue({
el: '#app',
data: {
parentData: {....},
},
components: {
comp2Level,
comp3Level,
comp4Level
},
methods: {
itemClick(item){
console.log('图片点击了', item)
}
}
})
</script>
</body>
</html>
上面伪代码如果看不懂,直接运行下面的真代码吧,vue.js自己导入就可以了:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
<title>Title</title>
</head>
<body>
<script src="../../js/vue.js"></script>
<div id="app">
<see-see :column-list="columnList">
<template slot-scope="seeSlotScope">
<commodity-list :commodity-list="seeSlotScope.seerow">
<template slot-scope="slotScope">
<commodity :commodity="slotScope.row" @parent-click="itemClick"></commodity>
</template>
</commodity-list>
</template>
</see-see>
</div>
<template id="seeSee">
<div>
<div class="row">
<div v-for="item in columnList">
<div>{{item.columnName}}</div>
<!-- 填充commodityList-->
<slot :seeRow="item.commodityList"></slot>
</div>
</div>
<div class="row">
seeSee圈footer
</div>
</div>
</template>
<template id="commodityList">
<div>
<div v-for="item in commodityList" class="col-md-4">
<slot :row="item">{{item}}</slot>
</div>
</div>
</template>
<template id="commodity">
<div>
<img style="height:100px":src="commodity.pic"></img>
<div>
<a @click="onCommodityClick(commodity)">{{commodity.desc}}</a>
</div>
</div>
</template>
<script>
const seeSee= {
template: '#seeSee',
props: {columnList:Array}
}
const commodityList={
template: '#commodityList',
props:{commodityList: Array}
}
const commodity = {
template: '#commodity',
props:{commodity: Object},
methods: {
onCommodityClick(commodity){
this.$emit('parent-click', commodity)
}
}
}
const app = new Vue({
el: '#app',
data: {
message: '你好',
columnList: [
{columnName: '有好货', commodityList:
[
{pic:'1.jpg',url:'http://1.jpg',desc:'第一张图片'},
{pic:'2.jpg',url:'http://2.jpg',desc:'第二张图片'},
{pic:'5.jpg', ur:'http://5.jpg',desc:'第五张图片'}
]
},
{columnName: '爱逛街', commodityList:
[
{pic:'3.jpg',url:'http://3.jpg',desc:'第三张图片'},
{pic:'4.jpg',url:'http://4.jpg',desc:'第四张图片'},
{pic:'6.jpg',url:'http://6.jpg',desc:'第六张图片'}
]
}
]
},
components: {
commodity,
commodityList,
seeSee
},
methods: {
itemClick(item){
console.log('图片点击了', item)
}
}
})
</script>
</body>
</html>
上面大神的文章的完整代码我也撸了一遍,有需要的拿走:作用域插槽三级例子
应用场景举例
现有的elementui的table,如果想要实现对列编辑、删除等功能,就使用了作用域插槽:https://element.eleme.cn/#/zh-CN/component/table