vm.$attrs
包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有显式地声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件,在创建高级别的组件时非常有用
vm.$listeners
包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件,在创建更高层次的组件时非常有用
代码实践:
1.父组件(FatherComponent.vue),给子组件传递数据,子组件如果不显式地用props接收,那么这些数据就作为普通的HTML特性应用在子组件的根元素上,而被$attrs所拥有
// 1.创建 FatherComponent.vue
// 2.引入子组件
// 3.并给子组件绑定属性:componyList,userInfos, 绑定事件: @sendMessage
// 4.并初始化方法 sendMessage
<template>
<div class='father-container'>
<div style="height: 30px; color: red; font-size: 16px;">我是爷爷组件</div>
<div>
<child-component
:componyList="componies"
@sendMessage="sendMessage"
:userInfos="personInfo"></child-component>
</div>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue'
export default {
name: 'FatherComponent',
components: {
ChildComponent
},
data() {
return {
personInfo: {
name: 'zhangsan',
age: 20,
gender: 'male',
houseList: ['houseA', 'houseB', 'houseC']
},
componies: ['componyA', 'componyB', 'componyC']
}
},
methods: {
// msg为孙子组件传递过来的数据
sendMessage(msg, msg1) {
console.log(`${msg} ${msg1}`)
}
}
}
</script>
<style lang='scss' scoped>
</style>
2.儿子组件(ChildComponent.vue)中间层,作为父组件和孙子组件的传递中介,在儿子组件中给孙子组件添加v-bind="$attrs",这样孙子组件才能接收到数据
// 1.创建子组件 ChildComponent.vue
// 2.给子组件传值,但不使用props接收
// 3.在子组件中引入孙子组件,并给孙子组件绑定 v-bind="$attrs" v-on="$listeners"
// 4.将是否继承父组件属性置为:inheritAttrs: true
<template>
<div class='child-container'>
<div style="height: 30px; color: green; font-size: 16px;">我是儿子组件</div>
<div>我是父组件的数据:{{this.$attrs}}</div>
<div>我是父组件的事件:{{this.$listeners}}</div>
<div>
<grand-son-component v-bind="$attrs" v-on="$listeners"></grand-son-component>
</div>
</div>
</template>
<script>
import GrandSonComponent from './GrandSonComponent.vue'
export default {
name: 'ChildComponent',
inheritAttrs: true,
components: {
GrandSonComponent
},
data() {
return {}
},
methods: {}
}
</script>
<style lang='scss' scoped>
</style>
3.孙子组件(GrandSonComponent.vue),在孙子组件中一定要显式地用props接收从父组件传递过来的数据,这样这些属性才可以传递给孙子组件
// 1.创建孙子组件 GrandSonComponent
// 2.通过给孙子组件绑定 $attrs 和 $listeners,这样在孙子组件直接就可以获取爷爷组件中的数据了
// 3.inheritAttrs: false
// 4.那么孙子组件如何和爷爷组件通信?
// (1) this.$listeners.sendMessage(param)
// (2) this.$emit('sendMessage', param)
<template>
<div class='grandson-container'>
<div style="height: 30px; font-size: 16px;">我是孙子组件</div>
<p>父传给孙子组件的数据1 userInfos: {{userInfos.name}} {{userInfos.age}} {{userInfos.gender}}</p><br>
<p>父传给孙子组件的数据2 componyList:{{componyList}}</p>
<button @click="triggerFatherEvent">Click Me</button>
</div>
</template>
<script>
export default {
name: 'GrandSonComponent',
// 不想继承所有父组件的数据,同时也不在组件根元素dom上显示
inheritAttrs: false,
components: {},
//在本组件中需要声明父组件绑定的属性,来接收数据
props: {
componyList: {
type: Array,
default: () => []
},
userInfos: {
type: Object,
default: () => {}
}
},
data() {
return {
msg: '我是来自 GrandChild 组件的消息',
msg1: '我是来自 GrandChild1 组件的消息'
}
},
methods: {
triggerFatherEvent() {
// 通过this.$listeners来触发爷爷组件中的事件,并且可以传递参数
this.$listeners.sendMessage(this.msg, this.msg1)
// 也可以emit直接触发,这两种方式都可以向上传递数据给父组件
// this.$emit('sendMessage', this.msg this.msg1)
}
}
}
</script>
<style lang='scss' scoped>
div {
p {
height: 30px;
}
}
</style>
点击孙子组件中的click事件,可以和爷爷组件通信