inheritAttrs
inheritAttrs在Vue官方文档上面的解释如下:
起初对于官方的定义不胜理解,写了一个demo之后才有了初步理解:
inheritAttrs 默认true状态时,当父组件在子组件引用标签上 传入一个子组件未定义(props中未定义)的属性,会将该属性添加到子组件的根节点上(变成一个自定义属性)这也解释了~ 默认状态下,给子组件引用标签上面直接添加 id class 。可以直接将这两个属性添加到子组件的根节点上~~
改为false时就会忽略这些未定义的属性 (class 和 style不受 false的影响)
让我们来看一个示例:
helloWorld.vue是父组件:
<template>
<div class="hello">
<h3>测试 inheritAttrs、$attrs、 $listeners</h3>
<child1 :text1="msg1" :text2="msg2" class="father" id="child" data-test="test"></child1>
</div>
</template>
<script>
import Child1 from './child1'
export default {
name: 'HelloWorld',
data () {
return {
msg1: '传入子组件的文字',
msg2: '传入二级子组件的文字'
}
},
components: {
Child1
},
child1.vue 为子组件:
<template>
<div class="child1-test">
<h3 @click="event1">{{text1}}</h3>
<child2 v-bind="$attrs" v-on="$listeners"></child2>
</div>
</template>
<script>
import Child2 from './child2'
export default {
name: 'child1',
props: {
text1: {
type: String,
default: ''
}
},
inheritAttrs: true,
这两段Vue组件中,在父组件的对子组件的引用中,除了传入了子组件中props定义的text1, text2、data-test、class、id都是未定义;此时子组件的inheritAttrs设置为true(默认即为true,此处写出来以便观察)。
查看页面中DOM结构如下:
如图所示,未定义的几个属性,都跑到子组件的根节点 div.child1-test 上面去了。
此时我们再将inheritAttrs属性设置为false观察:
除了class 依然被添加到子组件的根节点上面,其他属性都被忽略。
$attrs 和 $listeners
官方文档解释如下:
通俗的来讲:$attrs 是传入子组件中的自定义属性的对象(不包括子组件已定义的props 和 class、style属性);
依旧以上面代码为例,在子组件的生命周期mounted函数中,我们console.log一下 $attrs 此时控制台显示的内容如下:
然而$
l
i
s
t
e
n
e
r
s
就
是
可
以
通
过
listeners就是可以通过
listeners就是可以通过listeners向更深层次的组件传递事件。比如说三层组件的嵌套;如果子子组件想要将事件传递到父级,通常我们的写法是先将事件传递到子组件中,然后再通过子组件将事件传递到父组件。这样的写法,费时费力,修改困难。而通过$listeners就可以更加省力;
依旧是上面的示例,我们添加一个子子组件child2.vue。然后添加事件:
父组件:
<template>
<div class="hello">
<h3>测试 inheritAttrs、$attrs、 $listeners</h3>
<child1
:text1="msg1"
:text2="msg2"
class="father"
id="child"
data-test="test"
@event1="event1"
@event2="event2"
></child1>
</div>
</template>
<script>
import Child1 from './child1'
export default {
name: 'HelloWorld',
data () {
return {
msg1: '传入子组件的文字',
msg2: '传入二级子组件的文字'
}
},
components: {
Child1
},
methods: {
event1 (val) {
console.log(val)
},
event2 (val) {
console.log(val)
}
}
}
</script>
子组件:
<template>
<div class="child1-test">
<h3 @click="event1">{{text1}}</h3>
<child2 v-bind="$attrs" v-on="$listeners"></child2>
</div>
</template>
<script>
import Child2 from './child2'
export default {
name: 'child1',
props: {
text1: {
type: String,
default: ''
}
},
inheritAttrs: false,
mounted () {
console.log(this.$attrs)
},
components: {
Child2
},
methods: {
event1 () {
this.$emit('event1', '这是一级子组件点击事件')
}
}
}
</script>
子子组件:
<template>
<div>
<h3 @click.stop="event2">{{text2}}</h3>
</div>
</template>
<script>
export default {
name: 'child2',
props: {
text2: {
type: String,
default: ''
}
},
mounted () {
console.log(this.$attrs)
},
methods: {
event2 () {
this.$emit('event2', '二级子页面点击')
}
}
}
</script>
我们在子组件中使用v-on="$listeners"去传递事件。此时在页面中分别点击两个子组件中的文字,控制台效果:
补充: 用 v-bind="$attrs" 可以将父级自定义的属性对象 直接传入内部组件,这样的方式非常有用。
总结
Vue2.4 新增的这三个属性都非常的实用,对于结果共用组件封装,多层次组件嵌套上面,有非常大的帮助,本人也在持续学习中,对于某些知识理解尚且不足,希望在后续的学习中补充更多的实用场景。