$attrs,$listeners
vue实现组件通信的方式有:
- 父子通信
父组件向子组件传递通过props定义各个属性来传递,子组件向父组件传递通过$emit触发事件
ref也可以访问组件实例 - 跨级通信
vuex
bus
provide / inject
$attrs / $listeners - 解释 $attrs / $listeners
$attrs 将父组件中不被认为是props特性绑定的属性(即在父组件中或者中间组件中没有在props中定义的属性)传到孙组件中;
$listeners 将父组件标签上的自定义事件向下传递,其子组件可以直接通过$emit的方式调用;
父组件传值给子组件, 子组件可以全部不接受,然后通过v-bind=“$attrs”,传给孙组件, 然后孙组件直接使用props接受父组件传过来的所有属性普通的emit只能从子组件传到父组件, 通过$listeners可以实现从孙子组件把事件传到父组件中去, 不需要通过$emit逐层传递;
<!-- A.vue -->
<template>
<div>
<p>这是父组件</p>
<p>参数: name="fu" age="60" sex="nan-fu" address="shanghai-fu"</p>
<hr>
<B name="fu" age="60" sex="nan-fu" address="shanghai-fu" v-bind="$attrs" @setVal="getFuDetail"></B>
</div>
</template>
<script>
import B from './B'
export default {
components: {
B,
},
methods: {
getFuDetail(val) {
console.log('这是父组件的方法', val)
}
}
}
</script>
<style>
</style>
<!-- B.vue -->
<template>
<div>
<p>这是子组件</p>
<p>参数:name="zi" address="beijing-zi"</p>
<p>props: name</p>
<p>attrs: {{ $attrs }}</p>
<p>因为在B组件中props中包含name, 所以在attrs中,只有age,sex,address</p>
<hr>
<C name="zi" address="beijing-zi" v-on="$listeners"></C>
</div>
</template>
<script>
import C from './C.vue'
export default {
components: {
C,
},
props: {
name: { type: String, default: ''},
},
methods: {
getZiDetail() {
console.log('这是子组件的方法')
}
}
}
</script>
<style>
</style>
<!-- C.vue -->
<template>
<div>
<p>这是孙子组件</p>
<p>props: age</p>
<p>attrs: {{ $attrs }}</p>
<p>因为在C组件中props定义了age, 所以attrs中包含:父组件的name, sex, address,子组件的name, address,而子组件的name, address覆盖了父组件的name, address</p>
<hr>
</div>
</template>
<script>
export default {
props: {
age: { type: String, default: ''},
},
created() {
this.getSunDetail()
},
methods: {
getSunDetail() {
console.log('这是孙组件的方法')
this.$emit('setVal','通过$listeners触发父组件的事件')
}
}
}
</script>
<style>
</style>
通过$listeners在c组件触发了A组件的方法