欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Vue 学习——$attrs 和 $listeners 的用法

程序员文章站 2022-06-11 15:04:57
...

背景

学习 vueAdmin-template 这个项目时,看到两个属性 v-bind="$attrs"v-on="$linteners",于是就这两个属性的用法作了一下深入了解,通过一个简单的 demo 测试并理解了它们的用法。

我们知道,向子组件传递数据,是通过 v-bind 子类组件定义的 props 属性完成的,这只适用于单向、两层组件之间。同样地,事件传递也是在父组件中用 v-on 给子组件绑定事件,然后在子组件中通过 this.$emit 触发的、以达到修改父组件数据的目的。

那么,在多层嵌套组件中,顶层组件和最底层组件之间如何进行数据传递和事件触发呢?比如,A 组件引用了 B 组件,而 B 组件又引用了 C 组件,那么怎么在 A 中将数据传给 C ;在 C 中,怎么触发 A 中的方法呢?这就是 $attrs$listeners 的作用了。

$attrs

$attrs 是一个内置属性,指父组件传递的、除了自己定义的 props 属性之外的所有属性。例如 A 组件引用 B 组件,并为其绑定了三个属性 foo、coo、coo1:

<child-dom
  :foo="foo"
  :coo="coo"
  :coo1="foo"
  v-on:eventBindOnB="eventMethodInA"
>

B 组件【child-dom】中定义的属性为 props: ['foo', 'coo1'] 那么在 B 组件中打印 $attrs,就是除了 props 之外的属性 coo 。此时,B 又引用了组件 C 并向其传递了一个属性 coo :

<child-dom-child 
:coo="coo1" 
msg="B 组件的配置,但是 C 组件没有定义"
v-bind="$attrs" 
v-on="$listeners" 
@change="eventMethodInB"></child-dom-child>

而 C 组件【child-dom-child 】中定义了 props: ['coo', 'coo1'],此时在 C 组件中打印的$attrs是空的。学习所参考的项目中,需要在 B 组件中将 $attrs 绑定给 C ,但是测试发现,去掉这个绑定操作,C 中默认也是有$attrs 属性,也可以得到父组件的值。

$listeners

$listeners 包含了作用在这个组件上所有的监听器,即父组件绑定的全部监听事件,通过 v-on="$listeners",可以将这些事件绑定给它自己的子组件。

前面例子中 ,B 组件 为 C 组件最终绑定的监听事件等于 A 为 B 绑定的 eventBindOnB 事件,加上 B 为 C 绑定的 change 事件,可以在 C 中触发任何绑定在 C 上的事件。

C  的事件 = A 的监听事件 eventBindOnB +  B 的监听事件 change

此时,在 C 组件中定义一个按钮,就可以触发 A 组件的方法了:

元素定义:
<button @click="triggerMethodInA">点击</button>

方法定义
triggerMethodInA() {
   this.$emit('change')  //触发 B 的监听事件
   this.$emit(eventBindOnB) // 触发 A 的监听事件
}

A 组件中的方法定义:

methods: {
  eventMethodInA() {
    this.coo = 'I have been changed'
    this.msg = 'I have been changed11'
    console.log('change is trigger.')
  }
}

B 组件的方法定义:

methods: {
  eventMethodInB() {
   // this.coo1 = 'B Component change it '
    console.log('change is trigger.')
  }
}

据此,就完成了嵌套组件中,底层触发顶层事件的逻辑了。
点击 C 组件的按钮,最终调用 A 的某个方法,完成对 A 数据的修改操作:
Vue 学习——$attrs 和 $listeners 的用法

启示录

props 是父子组件传递数据的方式,是由父组件单向控制子组件属性的,所以不能在子组件中直接修改自己的 props 属性,否则 vue 会报错:

[Vue warn]: Avoid mutating a prop directly since the value will be overwritten 
whenever the parent component re-renders. 
Instead, use a data or computed property based on the prop's value. 
Prop being mutated: "coo1"

总结一下嵌套组件的数据和事件触发过程:
Vue 学习——$attrs 和 $listeners 的用法
本文参考 这篇文章 的案例,完成对 $attrs$listeners 用法的整理。

通过敲代码,熟悉了一些 ESLint 的规范,也顺便验证了一下老祖宗的智慧:无他,唯手熟能尔!