Vue 之 组件通信

在 Vue 的项目中,组件化开发我们带来的极大的便捷,但是同时,组件之间数据传递的问题也就随之而来。文本暂时先不使用 Vuex 完成组件之间的通信。

一、父组件 => 子组件

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
36
37
38
39
...
<!-- 父组件 -->
<template>
<div class="user-list">
<userItem :user="user"></userItem>
</div>
</template>
<script>
import userItem from './user/userItem.vue'
export default{
data(){
return{
user:{
name : 'summer',
age : 22 ,
gender : 'female'
}
}
},
components:{
userItem
}
}
</script>

<!-- 子组件 -->
<template>
<div class="user">
<div class="name">{{user.name}}</div>
<div class="age">{{user.age}}</div>
<div class="gender">{{user.gender}}</div>
</div>
</template>
<script>
export default{
props:['user']
}
</script>
...

父组件通过 props 将数据传递给子组件。
需要注意的是,子组件不能修改父组件的 props ,因为一个父组件下可能有多个子组件,如果某个子组件修改了父组件传递的 props ,很可能导致其他子组件也就跟着变化,最终导致整个应用的状态难以管理和维护。所以不允许子组件修改 props 。

二、子组件 => 父组件

子组件自定义事件,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。根据以上例子修改:

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
36
37
38
39
40
41
42
43
44
...
<!-- 父组件 -->
<template>
<div class="user-list">
<userItem :user="user" @addage="xxx"></userItem>
</div>
</template>
<script>
import userItem from './user/userItem.vue'
export default{
data(){
return{
user:{
name : 'summer',
age : 22 ,
gender : 'female'
}
}
},
components:{
userItem
},
methods:{
xxx(){
// 此处执行事件
}
}
}
</script>

<!-- 子组件 -->
<template>
<div class="user">
<div class="name">{{user.name}}</div>
<div class="age" @click="$emit('addage')">{{user.age}}</div>
<div class="gender">{{user.gender}}</div>
</div>
</template>
<script>
export default{
props:['user']
}
</script>
...

三、爷孙组件之间通信

爷孙组件之间的通信不想再多讲了,本质就是在爷孙组件之间再多加一级,形成两个父子组件通信。还可以使用标题五所示的 eventbus 来实现爷孙通信。

四、兄弟组件通信

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
36
37
38
// 父组件
<div>
<child-a @add="addB"></child-a>
<child-b ref="childb"></child-b>
</div>
<script>
export default{
methods:{
addB(){
this.$refs.childb.add();
}
}
}
</script>

// 子组件 a
<div class="a">
<button @click="$emit(add)"> b 增加</button>
</div>

// 子组件 b
<div class="a">
<p>{{num}}</p>
</div>
<script>
export default{
data(){
return {
num : 1
}
},
methods:{
add(){
this.num++;
}
}
}
</script>

五、非父子组件之间数据传递

有时候非父子关系的组件也需要通信。在简单的场景下,使用一个空的 Vue 实例作为中央事件总线。在这两个组件之间引入这个中央事件总线,然后 emit,on 相应的事件

1
2
3
4
5
6
7
let bus = new Vue()
// 触发组件 A 中的事件
bus.$emit('addage', 1)
// 在组件 B 创建的钩子中监听事件
bus.$on('addage', function (id) {
// ...
})

bus 总线方法跟事件订阅/分发模式很像。