返回

组件通信:利用$attrs和$listeners实现跨组件交流

前端

深入剖析attrs和listeners

$attrs:从父组件接收属性

attrs是一个只读属性,它包含了父组件传递给子组件的所有属性,但不包括作为props的属性。这意味着,子组件可以通过attrs访问父组件传递的任何数据,而这些数据不会触发props的更新。

例如,假设我们有一个父组件ParentComponent和一个子组件ChildComponentParentComponentChildComponent传递了两个属性messagecolor,但只有message属性是作为props传递的。那么,ChildComponent可以使用this.$attrs访问这两个属性,但只有this.message会触发props的更新。

$listeners:监听父组件触发的事件

$listeners是一个只读属性,它包含了子组件监听的所有事件。这意味着,父组件可以触发这些事件,子组件将能够收到并处理这些事件。

例如,假设我们有一个父组件ParentComponent和一个子组件ChildComponentParentComponent触发了一个名为increment的事件,ChildComponent监听了这个事件。那么,当ParentComponent触发increment事件时,ChildComponent将能够收到并处理这个事件。

attrs和listeners的优缺点

优点:

  • 允许子组件访问父组件传递的任意数据,而无需将这些数据声明为props。
  • 允许子组件监听父组件触发的任意事件,而无需在子组件中声明这些事件。
  • 可以在不修改子组件的情况下,动态地向子组件传递数据和事件。

缺点:

  • attrs和listeners的使用可能会导致组件之间的耦合度过高,从而使代码难以维护。
  • attrs和listeners的使用可能会导致代码的可读性降低,因为需要在不同的组件中查找数据和事件的传递和处理。

attrs和listeners与props、events和slot的关系

  • props: props是父组件向子组件传递数据的唯一官方方式。props必须在子组件中声明,并且只能传递声明的props。
  • events: events是子组件向父组件触发事件的唯一官方方式。events必须在子组件中声明,并且只能触发声明的events。
  • slot: slot是子组件向父组件提供内容的唯一官方方式。slot必须在子组件中声明,并且只能提供声明的slot。

attrs和listeners与props、events和slot的区别在于,它们不是官方的方式,而是Vue提供的额外功能,可以帮助组件之间进行通信。attrs和listeners的使用更加灵活,可以传递和处理任意数据和事件,但也会导致组件之间的耦合度过高和代码的可读性降低。

attrs和listeners的使用场景

  • 当需要动态地向子组件传递数据或事件时,可以使用attrs和listeners。
  • 当需要在子组件中使用父组件提供的任意数据或事件时,可以使用attrs和listeners。
  • 当需要在子组件中使用父组件提供的任意数据或事件,但又不想将这些数据或事件声明为props或events时,可以使用attrs和listeners。

attrs和listeners的使用示例

<!-- ParentComponent.vue -->
<template>
  <child-component :message="message" @increment="increment"></child-component>
</template>

<script>
export default {
  data() {
    return {
      message: 'Hello from parent!',
    }
  },
  methods: {
    increment() {
      this.message += '!'
    }
  }
}
</script>

<!-- ChildComponent.vue -->
<template>
  <div>
    <p>{{ message }}</p>
    <button @click="$emit('increment')">Increment</button>
  </div>
</template>

<script>
export default {
  props: ['message'],
  data() {
    return {
      color: 'red', // 不会被父组件传递,因为没有作为props声明
    }
  },
  computed: {
    attrs() {
      return this.$attrs // 包含父组件传递的所有属性,但不包括作为props的属性
    }
  },
  methods: {
    increment() {
      this.$emit('increment') // 触发父组件监听的increment事件
    }
  }
}
</script>

在上面的示例中,ParentComponentChildComponent传递了message属性和increment事件,ChildComponent通过this.$attrs访问了message属性,并通过this.$emit('increment')触发了increment事件。

结语

attrs和listeners是两个非常有用的属性,可以帮助组件之间进行通信。然而,在使用它们时需要注意,不要滥用它们,否则会使代码难以维护和理解。