1. 场景一
当我们有多层组件嵌套的时候 可以通过listeners 传递参数和事件,比如:
父组件A
<template>
<B :name="name" @say="say" />
</template>
<script>
export default {
data(){
return {
name:'Tom',
}
},
methods:{
say(){
console.log(`hello,${this.name}!`)
}
}
}
</script>
子组件要想真正实现多组件间相互传递 一般要在组件上加上inheritAttrs: false。
$attrs接收没有被props声明的数据
子组件B
<template>
<C v-bind="$attrs" v-on="listeners" />
</template>
<script>
export default {
inheritAttrs: false
}
</script>
孙组件C
<template>
<div>{{name}}</div>
<button @click="handleSay">打招呼</button>
</template>
<script>
export default {
props:{
name:String
},
methods:{
handleSay(){
this.$emit('say')
}
}
}
</script>
2. 场景二
很多时候我们需要对一些UI框架做二次封装,但是UI框架自带的各种属性配置又不能丢,需要在二次封装的时候源UI框架的属性依旧可以用,且不用每一个都去声明,可以用listeners 来实现,比如:
A组件
<template>
<myTable :header="tableHeader" :data="tableData" />
</template>
<script>
export default {
data(){
return {
tableHeader:[
{name:'企业名称',field:'name'},
{name:'企业规模',field:'size'},
],
tableData:[
{name:'xxx名称',size:'100-999人'},
{name:'yyy名称',size:'10-39人'},
],
}
}
}
</script>
myTable 组件
这里只声明了tableHeader和tableData 参数, 如果使用组件的时候 用户想要一个带有纵向边框的表格,原UI框架是支持 传参数 border=‘true’ 可满足需求,但是在我们二次封装后,并没有声明这个border 属性,怎么办? 继续添加声明props? 如果又有其他需求 想要size 属性呢? 再添加props吗? no no no ,这一点不好。怎么做才能让我们二次封装的组件能使用原来的属性配置又不用提前写一推props呢? 这就会用到$attrs啦,这也太好了吧。。。
<template>
<el-table v-bind="$attrs" v-on="listeners" >
<template v-for="item in tableHeader">
<el-table-column>... </el-table-column>
</template>
</el-table>
</template>
<script>
export default {
props:{
tableHeader:Array,
tableData:Array,
}
}
</script>