1、attrs属性就包含了所有父组件传来的数据(除开已经props声明了的)
当父组件传递了很多数据给子组件时,子组件没有声明props来进行接收,那么子组件中的attrs属性就包含了所有父组件传来的数据(除开已经props声明了的),子组件还可以使用v?bind="attrs属性就包含了所有父组件传来的数据(除开已经props声明了的),子组件还可以使用v-bind="attrs属性就包含了所有父组件传来的数据(除开已经props声明了的),子组件还可以使用v?bind="attrs"的形式向它的子组件(孙子组件)传递数据,孙子组件使用$attrs的方式和它的父组件原理类似。
// 父组件
<template>
<div>
<p>父级组件</p>
<div>
<button @click="changeMsg">更改数据</button>
</div>
<div>子组件数据:{{ fromchildData }}</div>
<child1 ref="child1" :msg="msg" v-model="fromchildData" :msg1="msg1" :msg2="msg2" :msg3="msg3" :msg4="msg4" @childData="childData"></child1>
</div>
</template>
<script>
import child1 from './child1.vue';
export default {
data() {
return {
msg: '父组件默认值',
msg1: 'parent数据1',
msg2: 'parent数据2',
msg3: 'parent数据3',
msg4: 'parent数据4',
fromchildData: ''
};
},
components: {
child1
},
methods: {
// 点击按钮更改数据
changeMsg() {
this.msg = '父组件主动改变值';
},
// 子组件的回调方法
childData(data) {
this.fromchildData = data;
},
}
};
</script>
// 子组件 child1.vue
<template>
<div class="child-1">
<p>--child1组件--</p>
<div>
<button @click="sendData">传递数据给父组件</button>
<button @click="getParentData">使用$parent</button>
<button @click="setListeners">使用listeners调用父级方法</button>
</div>
<div>
<el-input v-model="childStr" @input="confirm"></el-input>
<button @click="confirm">修改v-model数据</button>
</div>
<div>
<p>parent组件数据:{{ msg }}</p>
<!-- 子组件child1-child -->
<!-- <child1-child v-bind="$attrs" v-on="$listeners"></child1-child> -->
</div>
</div>
</template>
<script>
export default {
props: {
msg: {
type: String,
default: ''
},
// 通过v-model方式传值
value: {
type: String,
default: ''
}
},
data() {
return {
childStr: 'child String'
};
},
inheritAttrs: false,
mounted() {
console.log('child1组件获取$attrs', this.$attrs);
console.log('child1组件获取$listeners', this.$listeners);
},
methods: {
// 我们在父组件中使用v-model向child2子组件传递数据,子组件的props中使用默认的value属性接收,
// 在子组件中利用$emit触发父组件中默认input事件,此时传递的数据便会在子组件和父组件中发生变化,这就是数据双向绑定
// 通过$emit触发父组件的input事件,并将第二个参数作为值传递给父组件
confirm() {
this.$emit('input', this.childStr);
},
// 点击按钮,使用$emit向父组件传递数据
sendData() {
this.$emit('childData', '我是子组件向父组件提交的数据');
},
// 通过$parent方式获取父组件值
getParentData() {
console.log('父组件', this.$parent);
},
//如果存在多层级组件,无需使用emit的方式逐级向上触发事件,只需要使用$listerners就可以得到父组件中的自定义事件
setListeners() {
this.$listeners.childData('通过listeners调用方法');
}
}
};
</script>
<style scoped>
.child-1 {
border: 1px solid red;
}
</style>
?$attrs和$listeners的输出结果:
?
2、listeners属性和attrs属性类似,只是它们传递的东西不一样
?$listeners可以通过v-on的形式再次传递给下层组件,当父组件在子组件上定义了一些自定义的非原生事件时,在子组件内部可以通过listeners属性获取>父组件的自定义事件,它和attrs的区别很明显,attrs用来传递属性。
使用listeners的好处在于:如果存在多层级组件,无需使用emit的方式逐级向上触发事件,只需要使用$listerners就可以得到父组件中的自定义事件,相当于偷懒了。?
3、inheritAttrs
父组件传递了很多数据给子组件,子组件的props没有完全接收,那么父组件传递的这些数据就会渲染到HTML上,我们可以给子组件设置inheritAttrs 为false,避免这样渲染。
不设置inheritAttrs的属性如下:
?设置inheritAttrs为false后,
?
总结
attrs:用来会传递属性,除了class、style之类的,它是一个对象。 listeners:用来传递事件,除了原生事件,它也是一个对象。 attrs和listeners这两个属性可以解决多层组件之间数据和事件传递的问题。 inheritAttrs解决未使用props接收的数据的属性渲染
|