在使用vue框架中,经常会用到父子孙等多层次组件传参,如果采用props一层一层接收,就过于繁琐,官方提供$attrs和 $listeners来进行跨组件传参和方法处理
vue2版本
$attrs
主要是将父组件传过来的数据进行收集 ,如果props里面做了接收,那么$attrs则只收集没有接收的参数
inheritAttrs: false/ture,这个主要是是否将传递的参数显示在dom节点属性上 ,只会显示props没有接收的参数,如果props接收过的,则不在显示到节点
true:默认的显示
inheritAttrs: true,
a
false :则不显示
inheritAttrs: false,
a
<template>
<div id="app">
<div>vue2</div>
<father :info=info :info2=info2 v-on:eventOne="methodOne" ></father>
<button @click="modityInfo()">修改info值</button>
<button @click="modityInfo2()">修改info2值</button>
</div>
</template>
<script>
import father from './components/father.vue'
export default {
name: 'App',
data(){
return{
info:{
name:'张三',
id:1
},
info2:{
name:'李四',
id:2
}
}
},
components:{
father
},
我们从祖组件传递两个props对象 info 和info2
<template>
<div>
<p>Father组件</p>
<son v-bind="$attrs" v-on="$listeners" ></son>
<button @click="sendFather()">发送给父组件数据</button>
</div>
</template>
<script>
import son from './son.vue'
export default {
name:'FatherOne',
inheritAttrs: false,
// props:['info'],
mounted() {
console.log(this.$attrs)
// console.log(this.$listeners)
},
组件不适用props接收,则$attrs接收到全部参数
a
如果使用props接收全部或者某个,则$attrs就会排除接收的后参数,
export default {
name:'FatherOne',
inheritAttrs: false,
props:['info'],
mounted() {
console.log(this.$attrs)
// console.log(this.$listeners)
},
a
如果要继续进行孙组件等等,则需要继续传递$attrs,
<son v-bind="$attrs" v-on="$listeners" ></son>
接收原理一样
<template>
<div>
<p>Son组件组件</p>
<button @click="sendAnce()">发送给祖组件数据</button>
</div>
</template>
<script>
export default{
name:'SonTwo',
data(){
return{
}
},
props:{
info:{
default:()=>({})
},
info2:{
default:()=>({})
}
},
watch:{
info:{
handler(val){
console.log("监听info的值")
console.log(val)
},
deep:true,
immediate:true
},
info2:{
handler(val){
console.log("监听info2的值")
console.log(val)
},
deep:true,
immediate:true
}
},
孙组件可采用props接收或者赋值使用
$listeners
官方的描述是事件监听器,主要采用v-on="$listeners",传入内部组件,
个人的理解,类似于中间件,把父级的方法传递给子孙组件使用,由他们进行一个触发,把参数通过函数调用或者$emit方式调用把数据传回给父组件
<father :info=info :info2=info2 v-on:eventOne="methodOne" @senddata="getSenddata" ></father>
最外层组件传递两个方法,on:eventOne和senddata
mounted() {
// console.log(this.$attrs)
console.log(this.$listeners)
},
a
父组件接收到传递过来的方法
<template>
<div>
<p>Father组件</p>
<son v-bind="$attrs" v-on="$listeners" ></son>
<button @click="sendFather()">发送给父组件数据</button>
</div>
</template>
<script>
import son from './son.vue'
export default {
name:'FatherOne',
inheritAttrs: true,
mounted() {
// console.log(this.$attrs)
console.log(this.$listeners)
},
components:{
son
},
methods:{
sendFather(){
this.$listeners.eventOne('123')
this.$emit('eventOne',123)
this.$emit("senddata",456)
},
},
}
</script>
<style>
</style>
可以通过两种种方式实现给外层组件传参
第一种直接调用方法
第二种通过$emit方式
如果还需要继续深层次传递外层的方法 则需要继续传递v-on="$listeners",如果当前组件继续添加事件,则会合并外层一起传递给子组件,
这里个人觉得不是笼统传递不便于区分,建议以对象方式区分外层,父组件方法,就看官方后期了
<son v-bind="$attrs" v-on="$listeners" v-on:eventThree="methodThree" ></son>
那么孙组件也可以相同方式给外层组件传参或者方法调用
a
就会收到合并后的一个事件监听器,则可采取同样模式进行传递给父,祖数据
总的来说
v-on="$listeners"将所有方法又绑定到组件相应标签 ,是绑定方法(.native除外)
v-bind="$attrs" 将所有非props属性绑定到相应标签 ,是绑定属性(.class和style除外)
vue3版本
移除了$listeners,合并到$attrs中,那么,属性和方法统一合并到$attrs