当父组件传递了很多数据给子组件时,子组件没有声明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的输出结果:
$listeners可以通过v-on的形式再次传递给下层组件,当父组件在子组件上定义了一些自定义的非原生事件时,在子组件内部可以通过listeners属性获取>父组件的自定义事件,它和attrs的区别很明显,attrs用来传递属性。
使用listeners的好处在于:如果存在多层级组件,无需使用emit的方式逐级向上触发事件,只需要使用$listerners就可以得到父组件中的自定义事件,相当于偷懒了。
父组件传递了很多数据给子组件,子组件的props没有完全接收,那么父组件传递的这些数据就会渲染到HTML上,我们可以给子组件设置inheritAttrs 为false,避免这样渲染。
不设置inheritAttrs的属性如下:

设置inheritAttrs为false后,

attrs:用来会传递属性,除了class、style之类的,它是一个对象。 listeners:用来传递事件,除了原生事件,它也是一个对象。
attrs和listeners这两个属性可以解决多层组件之间数据和事件传递的问题。
inheritAttrs解决未使用props接收的数据的属性渲染