在多级组件嵌套需要传递数据时,通常会想到的方法是使用vuex或者bus传值,又或者事件触发传值,但是如果仅仅是传递一下数据,而不做中间的处理,用这几种方法感觉并不是特别的理想。所以就有了 listeners ,通常配合 inheritAttrs 一起使用。
inheritAttrs:默认值为 true。
默认情况下父作用域的不被认作 props 的 attribute 绑定 (attribute bindings) 将会“回退”且作为普通的 HTML attribute 应用在子组件的根元素上。当撰写包裹一个目标元素或另一个组件的组件时,这可能不会总是符合预期行为。通过设置inheritAttrs
到false
,这些默认行为将会被去掉。而通过 (同样是 2.4 新增的) 实例 property$attrs
可以让这些 attribute 生效,且可以通过v-bind
显性的绑定到非根元素上。查 看 官 网
感觉还是挺晦涩难懂的,简单的说就是 inheritAttrs:true 继承除props之外的所有属性;inheritAttrs:false 只继承class属性
attrs” 传入内部组件。当一个组件没有声明任何 props 时,它包含所有父作用域的绑定 (class 和 style 除外)。
listeners” 传入内部组件。它是一个对象,里面包含了作用在这个组件上的所有事件监听器,相当于子组件继承了父组件的事件。
话不多说,咱先上栗子
father.vue组件
<template>
<child :name="name" :infoObj="infoObj" @updateInfo="updateInfo" />
</template>
<script>
import Child from '../components/child.vue'
export default {
name: 'father',
components: { Child },
data () {
return {
name: 'Lily',
infoObj: {
from: '上海',
}
}
},
methods: {
updateInfo() {
console.log('update info');
}
}
}
</script>
child.vue 组件:
<template>
<grand-son :height="height" @addInfo="addInfo" v-bind="$attrs" v-on="$listeners" />
// 通过 $listeners 将父作用域中的事件,传入 grandSon 组件,使其可以获取到 father 中的事件
</template>
<script>
import GrandSon from '../components/grandSon.vue'
export default {
name: 'child',
components: { GrandSon },
props: ['name'],
data() {
return {
height: '180cm',
weight: '70kg'
};
},
created() {
console.log(this.$attrs);
// 结果:infoObj, 因为父组件共传来name, infoObj2个值,由于name被 props接收了,所以只有infoObj属性
console.log(this.$listeners); // updateInfo: f
},
methods: {
addInfo () {
console.log('add info')
}
}
}
</script>
grandSon.vue 组件:
<template>
<div>
{{ $attrs }} --- {{ $listeners }}
<div>
</template>
<script>
export default {
... ...
created() {
console.log(this.$attrs); // infoObj, height
console.log(this.$listeners) // updateInfo: f, addInfo: f
this.$emit('updateInfo') // 可以触发 father 组件中的updateInfo函数
}
}
</script>
总结:这种方式的传值对我来说不常用,感觉可读性不是很好。但当你在构建一个多层嵌套的组件时,对于组件层级嵌套比较深,使用props会很繁琐,或者项目比较小,不太适合使用 Vuex 的时候,可以考虑用它。