快应用笔记之组件通信

一、父传子

props

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
# 父组件
<import name="comp-part1" src="../Common/part"></import>
<template>
<div class="tutorial-page">
<text class="tutorial-title">页面父组件:</text>
<text>{{ data1 }}</text>
<text>{{ data2.name }}</text>

<!-- 子组件参数传递 -->
<comp-part1 prop1="{{data1}}" prop2-object="{{data2}}"></comp-part1>

</div>

</template>

<style lang="less">
.tutorial-page {
flex-direction: column;
padding: 20px 10px;
.tutorial-title {
font-weight: bold;
}
}
</style>

<script>
// 父组件
export default {
private: {
data1: 'string',
data2: {
name: 'object'
}
}
}
</script>
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
# 子组件
<template>
<div class="tutorial-page">
<text class="tutorial-title">子组件:</text>
<text>{{ prop1 }}</text>
<text>{{ prop2Object.name }}</text>
</div>
</template>

<style lang="less">
.tutorial-page {
flex-direction: column;
padding-top: 20px;
.tutorial-title {
font-weight: bold;
}
}
</style>

<script>
// 子组件
export default {
props: [
'prop1',
'prop2Object'
],
data: {},
onInit () {
console.info(`父组件传递下来的值:`, this.prop1, this.prop2Object)
}
}
</script>

二、双向的事件传递

父子组件之间的事件触发:$broadcast()、$dispatch()、子组件$emit()节点绑定的事件

1.向下传递:父组件触发,子组件响应;调用parentVm.$broadcast()完成向下传递,子组件 $on 响应,如:evtType1

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
# 父组件
<import name="comp-part1" src="../Common/part">
</import>
<template>
<div class="tutorial-page">
<text class="tutorial-title">页面父组件:</text>
<text onclick="evtType1Emit">触发$broadcast(),向下传递</text>
<!-- 子组件 -->
<comp-part1></comp-part1>
</div>
</template>

<style lang="less">
.tutorial-page {
flex-direction: column;
padding: 20px 10px;
.tutorial-title {
font-weight: bold;
}
}
</style>

<script>
// 父组件
export default {
data: {},
//触发$broadcast()
evtType1Emit () {
this.$broadcast('evtType1', { params: '额外参数', channel: 'test'})
}
}
</script>
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
45
# 子组件
<template>
<div class="tutorial-page">
<text class="tutorial-title">子组件:</text>
<text>1、父组件触发子组件响应,子组件接收的参数 e.detail:</text>
<text>{{ parentDate }}</text>
<text>2、e.type:</text>
<text>{{ Etype }}</text>
</div>
</template>

<style lang="less">
.tutorial-page {
flex-direction: column;
padding-top: 20px;
.tutorial-title {
font-weight: bold;
}
}
</style>

<script>
// 子组件
export default {
data: {
parentDate: '',
Etype: ''
},
onInit() {
// 绑定VM的自定义事件
//evtType1 要跟父组件 $broadcast 的对应一致
//responseEvent 子组件响应以后的操作
this.$on('evtType1', this.responseEvent )
},
responseEvent (e) {
console.info('子组件evt', e)
console.info(`子组件:事件响应: `, e.type, e.detail)
console.info(`evt.detail.channel: `, e.detail.channel)
this.parentDate = JSON.stringify(e.detail);
this.Etype = JSON.stringify(e.type);
// 结束事件传递
// evt.stop()
}
}
</script>

2.向上传递:子组件触发,父组件响应;调用childVm.$dispath()完成向上传递,如:evtType2

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
# 子组件
<template>
<div class="tutorial-page">
<text class="tutorial-title">子组件:</text>
<text onclick="evtType2Dispatch">$dispatch触发向上传递</text>
<text onclick="evtType2Emit">$emit触发向上传递</text>
</div>
</template>

<style lang="less">
.tutorial-page {
flex-direction: column;
padding-top: 20px;
.tutorial-title {
font-weight: bold;
}
}
</style>

<script>
// 子组件
export default {
data: {},
onInit() {

},
evtType2Dispatch () {
this.$dispatch('evtType2', { params: '$dispatch', respose: '向上传递' })
},
evtType2Emit () {
this.$emit('evtType3', { params: '$emit', respose: '向上传递' })
}
}
</script>
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
# 父组件
<import name="comp-part1" src="../Common/part">
</import>
<template>
<div class="tutorial-page">
<text class="tutorial-title">页面父组件:</text>
<text>$dispatch: {{ childData }}</text>
<text>$emit: {{ childData2 }}</text>
<!-- 子组件 evt-type2 => evtType2 -->
<comp-part1 onevt-type2="parentResponse" onevt-type3="parentResponse3"></comp-part1>
</div>

</template>

<style lang="less">
.tutorial-page {
flex-direction: column;
padding: 20px 10px;
.tutorial-title {
font-weight: bold;
}
}
</style>

<script>
// 父组件
export default {
data: {
childData: '',
childData2: ''
},
parentResponse(e) {
console.log(`父组件事件响应1: `, e);
console.info(`父组件:事件响应: `, e.type, e.detail)
this.childData = JSON.stringify(e.detail)
// 结束事件传递
// evt.stop()
},
parentResponse3(e) {
this.childData2 = JSON.stringify(e.detail)
}
}
</script>

三、兄弟组件通信

传统的兄弟等非父子组件之间通信,是通过Publish/Subscribe模型来完成。
开发者如果想要使用这样的能力,当然可以自己写一个Pub/Sub模型实现通信解耦;当然在业务逻辑相对简单的情况下,也可以使用ViewModel本身的事件绑定来处理:$on(),$emit()。

子组件定义了Sub端的逻辑处理,有processMessage()、customEventInVm2(),后者同使用$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
# 组件2 part2
<template>
<div class="tutorial-page">
<text class="tutorial-title">自定义组件2:</text>
<text>处理消息:{{msg}}</text>
<text>事件内容:{{eventDetail}}</text>
</div>
</template>

<style lang="less">
.tutorial-page {
flex-direction: column;
padding: 20px 10px;
.tutorial-title {
font-weight: bold;
}
}
</style>

<script>
// 子组件: part2
export default {
props: [],
data() {
return {
msg: null,
eventDetail: null
}
},
processMessage(msg) {
const now = (new Date).toISOString()
this.msg = `${now}: ${msg}`
},
/**
* 通过events对象:绑定事件
*/
events: {
customEventInVm2(evt) {
const now = (new Date).toISOString()
this.eventDetail = `${now}: ${evt.detail}`
}
}
}
</script>

另外一个兄弟组件可以通过父组件中建立相互引用达到相互持有ViewModel的目的,通过在生命周期onReady()中执行establishRef()实现,如下代码所示:

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
45
46
47
48
# 父组件
<import name="comp-part2" src="../Common/part2"></import>
<import name="comp-part3" src="../Common/part3"></import>

<template>
<div class="tutorial-page">
<!-- 兄弟VM通信 -->
<comp-part2 id="sibling2"></comp-part2>
<comp-part3 id="sibling3"></comp-part3>

<text @click="pppp">父组件调用子组件方法</text>
</div>
</template>

<style lang="less">
.tutorial-page {
flex-direction: column;
padding: 20px 10px;
.tutorial-title {
font-weight: bold;
}
}
</style>

<script>
// 父组件
export default {
onReady() {
this.establishRef()
},
/**
* 建立相互VM的引用
*/
establishRef() {
const siblingVm2 = this.$vm('sibling2')
const siblingVm3 = this.$vm('sibling3')
console.info(siblingVm2)
console.info(siblingVm3)
siblingVm2.parentVm = this
siblingVm2.part2 = siblingVm3 //将组件3整个赋值给组件2的part2属性,打印可以看到part2属性内部就拥有组件3定义的一些方法
siblingVm3.parentVm = this
siblingVm3.part3 = siblingVm2 //将组件2整个赋值给组件3的part3属性
},
pppp() {
this.$vm('sibling2').processMessage();
}
}
</script>

this.$vm(id)可以获取到组件的属性跟方法

那么另外一个子组件的Pub端定义就很简单了,执行sendMesssage()即可完成触发,如下代码所示:

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
# 子组件 part3
<template>
<div class="tutorial-page">
<text class="tutorial-title">自定义组件3:</text>
<text onclick="sendMesssage">点击发送消息</text>
</div>
</template>

<style lang="less">
.tutorial-page {
flex-direction: column;
padding: 20px 10px;
.tutorial-title {
font-weight: bold;
}
}
</style>

<script>
// 子组件: part3
export default {
sendMesssage() {
// 父组件中把组件2赋值在 part3下
if (this.part3) {
// Way1. 调用方法
this.part3.processMessage('兄弟之间通信的消息内容')
// Way2. 触发事件
this.part3.$emit('customEventInVm2', '兄弟之间通信的消息内容')
}
},

}
</script>