$attrs

如果向一个子组件传递数据attribute时,该子组件并没有相应prop定义的attribute时。这些 attribute 会被添加到这个组件的根元素上。
示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//父组件
<template>
<div class="home">
以下为组件S1的内容
<S1 :foo='foo' :eoo='eoo'/>
</div>
</template>
...
import S1 from '@/components/S1.vue'
data(){
return{
foo:'I am foo',
eoo:'I am eoo',
}
},
components:{
S1
},
...
1
2
3
4
5
6
7
8
9
10
11
12
//子组件 S1
<template>
<div>
{{foo}}
</div>
</template>
...
data(){
return{}
},
props:['foo'],
...

我们可以看到只有foo才会显示,而eoo则被添加到根元素中了,即便页面添加了也不会显示的。
如果不希望组件的根元素继承 attribute,你可以在组件的选项中设置 inheritAttrs: false。再配合实例的 $attrs property 使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//修改后的子组件S1,添加$attrs,并查看其值
<template>
<div>
<p>foo:{{foo}}</p>
<p>attrs:{{$attrs}}</p>
</div>
</template>
...
data(){
return{}
},
props:['foo'],
inheritAttrs: false,
...

我们可以看到在组件的选项中设置 inheritAttrs: false后,组件没有相应prop定义的attribute将会被绑定到$attrs上。

通过对象取值的方法是行不通的,比如$attrs.eoo,但是我们可以通过v-bind="$attrs"传入其内部组件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//修改后的子组件S1,引入子组件S1Child
<template>
<div>
<p>foo:{{foo}}</p>
<p>attrs:{{$attrs}}</p>
以下为组件S1Child的内容
<s1-child v-bind="$attrs"></s1-child>
</div>
</template>
...
import S1Child from '@/components/S1Child.vue'
data(){
return{}
},
components:{
S1Child,
},
props:['foo'],
inheritAttrs: false,
...
//子组件S1Child
<template>
<div>
<p>eoo:{{eoo}}</p>
</div>
</template>
...
props:['eoo'],
...

我们可以看到,通过$attrs可以接收组件没有相应prop定义的attribute,并通过prop让其子子组件接收到。那么组件S1Child的信息怎么传递给其父父组件呐?$listeners

$listeners

包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//修改后的父组件,添加绑定事件@upData
<template>
<div class="home">
以下为组件S1的内容
<S1 :foo='foo' :eoo='eoo' @upData="getS1ChidData"/>
</div>
</template>
...
import S1 from '@/components/S1.vue'
data(){
return{
foo:'I am foo',
eoo:'I am eoo',
}
},
components:{
S1
},
methods:{
getS1ChidData(value){
console.log('这是组件S1Chid传过来的数据:',value)
}
}
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//修改后的子组件S1,绑定$listeners
<template>
<div>
<p>foo:{{foo}}</p>
<p>attrs:{{$attrs}}</p>
以下为组件S1Child的内容
<s1-child v-bind="$attrs" v-on="$listeners"></s1-child>
</div>
</template>
...
import S1Child from '@/components/S1Child.vue'
data(){
return{}
},
components:{
S1Child,
},
props:['foo'],
inheritAttrs: false,
...
//子组件S1Child
<template>
<div>
<p>eoo:{{eoo}}</p>
<button @click="startUpData">upData</button>
</div>
</template>
...
props:['eoo'],
methods:{
startUpData(){
this.$emit('upData','我是S1Child传过来的数据!')
}
}
...

通过点击组件S1Child中的按钮触发当前实例上的upData事件,但是并不能直接触发非父组件的upData事件,需要通过v-on="$listeners"也就通过$listeners接收了父组件的事件监听器并传给内部组件。