您的位置:首页 > 教育 > 培训 > $attrs/$listeners实现爷孙组件通信

$attrs/$listeners实现爷孙组件通信

2025/5/25 18:00:11 来源:https://blog.csdn.net/a123456234/article/details/142032876  浏览:    关键词:$attrs/$listeners实现爷孙组件通信

$attrs/$listeners实现爷孙组件通信

$attrs$listeners 是两个特殊的对象,它们分别用来处理父组件传递给子组件的未声明为 props 的属性和事件。这两个特性可以用来实现较为复杂的组件通信,尤其是当涉及到多层级的组件时,比如爷孙组件之间的通信。

$attrs: 当一个组件接收到父组件传递的属性,但这些属性没有被声明为 props 时,它们会被收集到 $attrs 对象中。$attrs 可以用来将这些未声明的属性传递给更深层次的子组件。

$listeners: 类似于 $attrs$listeners 包含了父组件传递给当前组件的所有事件监听器。它允许将这些监听器传递给子组件,将子组件 $emit 方法传递过来的事件传递给爷组件,调用从而实现事件的传递。

实现原理

属性传递:爷爷组件将一些属性传递给父组件,父组件通过 $attrs 将这些属性传递给孙子组件。

事件监听器传递:爷爷组件绑定了一些事件监听器到父组件,父组件通过 $listeners 将这些监听器传递给孙子组件。

优点
  • 灵活性:$attrs$listeners 提供了一种灵活的方式来传递未声明的属性和事件,使得组件可以更容易地适应不同的使用场景。

  • 简化通信:通过 $attrs$listeners,可以简化多层组件之间的通信,避免了显式地在每一层都定义 props 和事件转发。

  • 扩展性:允许组件在不知道具体属性和事件的情况下接收和传递它们,增加了组件的扩展性和复用性。

缺点
  • 类型安全问题:在 TypeScript 等强类型语言中使用 $attrs$listeners 可能会导致类型推断的问题,使得类型检查变得困难。

  • 调试困难:由于 $attrs$listeners 包含的是未明确声明的内容,这可能使得调试变得更加困难。

  • 性能影响:频繁地使用 $attrs$listeners 可能会影响性能,尤其是在大型应用中,因为每次父组件的属性或事件变化时,都会触发 $attrs$listeners 的更新。

  • 可维护性:过度依赖 $attrs$listeners 可能会使得组件之间的关系变得模糊,增加代码的复杂性和维护难度。

vue2.x 使用

在vue2中,$attrs 是组件的一个实例属性,包含了父作用域中 不作为 prop 被识别的属性。

grandpa.vue (爷组件)

// grandpa.vue<template><div class="grandpa"><h2>爷组件</h2><div>{{ msg }}</div><parent :message="message" :message2="message2" @sendGradpaMessage="getMessage"/></div>
</template><script>
import parent from './parent.vue';export default {name: 'grandpa',data() {return {message: 'This is some shared data1',message2: 'This is some shared data2',msg:""}},components: {parent},methods:{getMessage(msg){console.log('msg::: ', msg);this.msg = msg},}
}
</script>

parent.vue (父组件)

// parent.vue<template><div class="parent"><h2>父组件</h2><div>{{ message }}</div><son v-bind="$attrs" v-on="$listeners"/></div>
</template><script>
import son from './son.vue';export default {name: 'parent',data() {return {}},components: { son },computed: {message() {// 从 $attrs 中删除已定义的 propconsole.log('this.$attrs::: ', this.$attrs);const { message} = this.$attrs;return message;}},
}
</script>

son.vue (孙组件)

// son.vue<template><div class="son"><h2>孙组件</h2><div>{{ $attrs.message }}</div> <div>{{ message }}</div> <el-button type="primary" @click="sendMessage">发送消息</el-button></div>
</template><script>
export default {name: 'son',data() {return {}},computed: {message() {// 从 $attrs 中删除已定义的 propconsole.log('this.$attrs::: ', this.$attrs);const { message2} = this.$attrs;return message2;}},methods: {sendMessage(){const msg = 'Hello from son component!';this.$emit('sendGradpaMessage', msg)}}
}
</script>

上述示例中:

  • grandpa.vue 组件提供了 message, message2 两个参数。

  • parent.vue 组件通过 $attrs 接收了 message 参数,并在模板中使用 message

  • son.vue 组件通过 $attrs 接收了 message2 参数,并在模板中使用 message,同时通过点击按钮使用 $emit 方法将参数 msg 传给了 parent.vue 组件,parent.vue 通过 $listeners 将事件传递给 grandpa.vue

vue3.x 使用

在 Vue 3 中,$attrs$listeners 的使用有一些变化,特别是在 $listeners 的处理上。Vue 3 已经不再单独提供 $listeners,而是将事件监听器和其他属性一起放在 $attrs 中。这意味着在 Vue 3 中,你需要通过 $attrs 来传递所有的属性和事件监听器。

grandpa.vue (爷组件)

// grandpa.vue<template><div class="grandpa"><h2>爷组件</h2><div>{{ receive }}</div><parent :message="message" :message2="message2" @sendGrandpaMessage="getMessage" /></div>
</template><script setup lang="ts" name="grandpa">
import { ref } from 'vue';import parent from './parent.vue';// 定义一个可变的值
const message = ref('Hello from grandpa');
const message2 = ref('Hello from Parent');// 定义一个接收消息
const receive = ref('111');// 接收子组件传的参数
const getMessage = (msg: string) => {console.log('msg::', msg);receive.value = msg
};
</script>

parent.vue (父组件)

// parent.vue<template><div class="parent"><h2>父组件</h2><div>{{ message2 }}</div><div>{{ $attrs }}</div><son v-bind:="$attrs" /></div>
</template><script setup lang="ts" name="parent">
import son from './son.vue';defineProps(['message2']);
</script>

son.vue (孙组件)

// son.vue<template><div class="son"><h2>孙组件</h2><div>{{ message }}</div><el-button type="primary" @click="sendMessage()">发送消息</el-button></div>
</template><script setup lang="ts" name="son">
import { defineProps, defineEmits } from 'vue';defineProps(['message',]);const emits = defineEmits(['sendGrandpaMessage']);// 处理事件
function sendMessage() {const msg = 'Hello from child';emits('sendGrandpaMessage', msg);
}
</script>

上述示例中:

  • grandpa.vue 组件提供了 message, message2 两个参数和 sendGrandpaMessage 方法。

  • parent.vue 组件通过 $attrs 接收了 message2 参数,并在模板中使用 message2

  • son.vue 组件通过 $attrs 接收了 message 参数,并在模板中使用 message,同时通过点击按钮使用 emit 将参数 msg 传给了 parent.vue 组件,parent.vue 通过 $attrs 将事件传递给 grandpa.vue

总结

$attrs$listeners 是 Vue.js 提供的一种机制,用于处理未声明的属性和事件的传递。它们在特定场景下非常有用,特别是在需要灵活传递属性和事件的情况下。然而,它们也有一定的局限性,如类型安全问题、调试困难等。因此,在实际开发中,应该根据具体情况权衡是否使用 $attrs$listeners,并在必要时使用它们来增强组件的灵活性和扩展性。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com