vue中组件间的通信方式(二)

$attrs和 $listeners

第一种方式props和 $ emit处理父子组件之间的数据传输有一个问题:如果多层嵌套,父组件A下面有子组件B,组件B下面有组件C,这时如果组件A想传递数据给组件C怎么办呢?
如果采用第一种方法,我们必须让组件A通过prop传递消息给组件B,组件B在通过prop传递消息给组件C;要是组件A和组件C之间有更多的组件,那采用这种方式就很复杂了。从Vue 2.4开始,提供了 $attrs和 $listeners来解决这个问题,能够让组件A之间传递消息给组件C。

1)$attrs

官方文档:包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind=“$attrs” 传入内部组件——在创建高级别的组件时非常有用。
$ attrs只代表的是那些没有被声明为props的属性,如果某个prop被子组件中声明了(就是这个属性已经在子组件的props中了),在子组件中的 $ attr会把声明的prop剔除。
也就是说:一个组件在父组件中被引用,$attrs就是组件标签上的静态属性值(attr)和动态属性值(:attr)的对象集合,这个集合不包含class, style和事件属性。

// 父组件
<child-com class="com" name="attr" :foo="foo" :boo="boo" :coo="coo" :doo="doo" @click="test"></child-com>
...
data() {
  return {
    foo: 'Hello World!',
    boo: 'Hello Javascript!',
    coo: 'Hello Vue',
    doo: 'Last'
  }
},
...

// child-com.vue
 export default {
  name: 'childCom',
  components: {
    childCom2
  },
  created() {
    console.log(this.$attrs) // {name: "attr", foo: "Hello World!", boo: "Hello Javascript!", coo: "Hello Vue", doo: "Last"}
  }
}

如果组件中声明了 $ prop,那么 $ attrs中和$prop中相同的属性会被移除。

<!--  child-com.vue -->
 export default {
    
    
  name: 'childCom',
  props: ['foo'], // foo被声明
  components: {
    
    
    childCom2
  },
  created() {
    
    
    console.log(this.$attrs) // {name: "attr", boo: "Hello Javascript!", coo: "Hello Vue", doo: "Last"}
  }
}

如果childCom里的子组件还用到foo,可以继续将foo传给子组件。

<template>
  <div>
    <p>foo: {
    
    {
    
    foo}} </p>
    <child-com2 :foo="foo" v-bind="$attrs"></child-com2>
  </div>
</template>

<script>
const childCom2 = () => import('./childCom2.vue')
export default {
    
    
  name: 'childCom1',
  props: ['foo'], // foo作为props属性绑定
  inheritAttrs: false,
  components: {
    
    
    childCom2
  },
  created() {
    
    
    console.log(this.$attrs) // {name: "attr", boo: "Hello Javascript!", coo: "Hello Vue", doo: "Last"}
  }
}
</script>
<!-- childCom2.vue -->
created() {
    
    
    console.log(this.$attrs) // {foo: "Hello World!", name: "attr", boo: "Hello Javascript!", coo: "Hello Vue", doo: "Last"}
  }

与 $ prop作比较,$ props是必须要在组件中注册props才能够拿到值,因此在嵌套层级比较深的组件中$attrs取值更加方便。

2)$listeners

包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on=“$listeners” 传入内部组件——在创建更高层次的组件时非常有用。
$ listeners是组件中的内置属性,它的值是父组件(不含.native修饰器的)v-on事件监听器。
组件可以通过在自己的子组件上使用v-on=“$ listeners”,进一步把值传给自己的子组件。如果子组件已经绑定$listeners中同名的监听器,则两个监听器函数会以冒泡的方式先后执行。
父组件:

 <template>
    <div class="test">
        <child  v-bind="{name, sex, age}" v-on="{changeName,changeAge}"></child>
    </div>
</template>

<script>
import child from './child'

export default {
    
    
    data() {
    
    
        return {
    
    
          name: '张三',
          sex: '男',
          age: 11,
        }
    },
    components: {
    
    
        child
    },
    methods: {
    
    
        changeName(name) {
    
    
            this.name = name
        },
        changeAge(age) {
    
    
            this.age = age
        }
    }
}
</script>

子组件child.vue

<template>
    <div class="child">
        child组件的$attrs {
    
    {
    
    $attrs}}
        <child-child v-bind="$attrs" v-on="$listeners" @showAttrs="showAttrs"></child-child>
    </div>
</template>

<script>
import childChild from  './child-child'
export default {
    
    
    name: "child",
    props: ['name'],
    inheritAttrs: false,
    created() {
    
    
        console.log('child', this.$listeners) 
    },
    components: {
    
    
        childChild
    },
    methods: {
    
    
        showAttrs() {
    
    
            console.log(this.$attrs)
        }
    }
}
</script>

孙子组件:child-child.vue

<template>
    <div class="child-child">
        child-child组件的$attrs {
    
    {
    
    $attrs}}
    </div>
</template>

<script>
export default {
    
    
    name: "child-child",
    inheritAttrs: false,
    created() {
    
    
      console.log('child-child',this.$listeners)  
    }
}
</script>

打印结果:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_44482048/article/details/128895069