我们都知道父子组件的通信可以使用props
和$emit
的方式,但是如果进行父子组件和孙子组件的通讯使用props
和$emit
的话就比较复杂了,需要层层传递。而,$attrs
和$listeners
就减少了子组件的代码。它打通了父组件和孙组件之间的阻碍。
当父组件传数据给子组件的时候,如果子组件的props没有进行接收,那数据就会被收集到子组件的$attrs
里面,在子组件上使用v-bind="$attrs"
可以直接将值传给当前组件的子组件(也就是孙组件),即使是v-model依旧可以传递。
默认情况下父作用域的不被认作
props
的attribute
绑定 (attribute bindings
) 将会“回退”且作为普通的HTML attribute
应用在子组件的根元素上。当撰写包裹一个目标元素或另一个组件的组件时,这可能不会总是符合预期行为。通过设置inheritAttrs
到false
,这些默认行为将会被去掉。而通过 (同样是 2.4 新增的) 实例property $attrs
可以让这些attribute
生效,且可以通过v-bind
显性的绑定到非根元素上。
父组件
<template>
<div class="app">
<h3>我是爷爷组件</h3>
<Parent :data1="data1" :data2="data2" :data3="data3" @fun1="fun1" @fun2="fun2"></Parent>
</div>
</template>
<script>
import Parent from './components/Parent.vue'
export default {
name: "App",
components: {
Parent
},
data() {
return {
data1: '数据1',
data2: '数据2',
data3: '数据3'
}
},
methods: {
fun1(val) {
console.log('通过子组件触发', val);
},
fun2(val) {
console.log('通过子组件触发', val);
}
}
}
</script>
子组件
<template>
<div class="parent">
<h3>我是父组件</h3>
<Son v-bind="$attrs" v-on="$listeners"></Son>
</div>
</template>
<script>
import Son from './Son'
export default {
//禁用将数据显示在组件根元素的默认操作
inheritAttrs: false,
name: 'Parent',
props: {
data1: {
type: String,
default: ''
}
},
components: {
Son
},
created() {
console.log(this.$attrs, this.$listeners, 'this.$attrs,this.$listeners'); //data2: "数据2", data3: "数据3",fun1, fun2
},
}
</script>
孙组件
<template>
<div class="son">
<h3>我是子组件</h3>
这是爷爷的数据{{user}} <br>
这是自己的数据{{myUser}}<br>
<button @click="toParent">传递数据给父组件</button>
</div>
</template>
<script>
import Son from './Son'
export default {
name: 'Son',
components: {
Son
},
props: {
//接收父组件的数据
data2: {
type: String,
default: ''
},
data3: {
type: String,
default: ''
}
},
created() {
console.log(this.data2, this.data3, '$attrs');
},
methods: {
toParent() {
//触发父组件的方法
this.$emit('fun1', '我是孙组件数据')
}
}
}
</script>