深圳幻海软件技术有限公司 欢迎您!

快应用的事件监听机制和组件间通信

2023-02-26

说起事件,做前端开发的朋友一定不会陌生。事件,即网页上的一系列行为,可以是浏览器行为,如页面完成了加载,页面关闭;或是用户操作行为,如用户输入操作,用户点击按钮等,这些行为会被JavaScript监测到,并执行相应的逻辑代码。可以说,前端的交互行为与事件机制息息相关,对于前端开发者而言,掌握好事件机

说起事件,做前端开发的朋友一定不会陌生。事件,即网页上的一系列行为,可以是浏览器行为,如页面完成了加载,页面关闭;或是用户操作行为,如用户输入操作,用户点击按钮等,这些行为会被JavaScript监测到,并执行相应的逻辑代码。可以说,前端的交互行为与事件机制息息相关,对于前端开发者而言,掌握好事件机制是绝对必要的。

所谓组件,即封装起来的具有独立功能的UI部件。试想,如果开发一个复杂的页面,开发者把所有的UI部分写在一个文件中,这样的代码显然可维护性很低。但我们如果用组件的方式去重新思考UI构成,将UI上每一个功能相对独立的模块定义成组件,然后将小的组件通过组合或者嵌套的方式构成大的组件,进而完成整体UI的开发。这样,我们不仅提高了代码的复用性,且整体结构清晰,维护性则大大提高。

组件化界面

本文将介绍在快应用开发中,事件相关的主要API以及事件的监听、触发机制,同时会介绍快应用中组件是如何通信的。阅读本文前,建议先了解快应用相关基础知识。

自定义事件的监听、移除与触发

$on 用于监听自定义事件;$off移除对应的事件监听;$emit()、$dispatch()、 $broadcast()等方法可用于触发事件。

$on(evtName, fnHandler)事件

在当前页面注册监听事件, 可监听$emit()、 $dispatch()、 $broadcast()等触发的自定义事件,不能用于注册组件节点的事件响应。

示例如下:

export default {  
onInit(){  
this.$on('customEvtType1'this.customEvtType1Handler)  
},  
customEvtType1Handler(evt){  
// 事件类型,事件参数  
console.info(`触发事件:类型:${evt.type}, 参数: ${JSON.stringify(evt.detail)}`);  
 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

解释一下

'customEvtType1'为该组件上自定义的事件名称,customEvtType1Handler为当'customEvtType1'事件被触发时,要执行的回调函数。

$off(evtName, fnHandler)

移除事件监听,参数 fnHandler 为可选,传递仅移除指定的响应函数,不传递则移除此事件的所有监听。

示例如下:

export default {  
removeEventHandler () {  
// 不传递fnHandler:移除所有监听  
this.$off('customEvtType1' 
// 传递fnHandler:移除指定的监听函数  
this.$off('customEvtType1'this.customEvtType1Handler)  
 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

页面的交互中可能会遇到一些非手动触发的需求,$emit() 通过触发当前实例上的事件,达到动态触发事件的行为,类似jquery中的trigger方法。

$emit(evtName, evtDetail)

触发当前实例监听事件函数,与 $on() 配合使用,注意:$emit() 目前只触发 $on 所监听的事件

示例如下:

export default {  
emitEvent () {  
this.$emit('customEvtType1', { params: '参数内容' })  
 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

监听原生组件事件

原生组件即框架自带的组件,如div,text等等,其支持一系列事件,如通用事件(如:click, disappear)、组件专有事件(如:focus)。完整的原生组件列表以及事件可在快应用官网查询到。

开发者可以在事件回调函数中,获取到当前触发组件的信息,并进行进一步的操作。

在响应函数执行时通过target获取,如:onClickHandler

在响应函数绑定时传递参数,如:onClickHandler2

示例如下:

<template 
<div class="tutorial-page" 
<text id="elNode1" item-flag="{{ argName + 1 }}" onclick = "onClickHandler">组件节点1</text>  
<text id="elNode2" item-flag="{{ argName + 2 }}" onclick = "onClickHandler2('参数1', argName)">组件节点2</text>  
</div> 
 
</template 
<style lang="less" 
.tutorial-page {  
flex-direction: column;  
 
</style> 
 
<script>  
export default {  
data () {  
return {  
argName: '动态参数'  
 
}, 
 
onClickHandler (evt) {  
// 事件类型,参数详情  
console.info(`触发事件:类型:${evt.type}, 详情: ${JSON.stringify(evt.detail)}`);  
if (evt.target) {  
console.info(`触发事件:节点:${evt.target.id}, ${evt.target.attr.itemFlag}`)  
 
}, 
 
onClickHandler2 (arg1, arg2, evt) {  
// 事件类型,事件参数,target  
console.info(`触发事件:类型:${evt.type}, 参数: ${arg1}, ${arg2}`);  
 
 
</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.

解释一下

onClickHandler函数如果不传参数,默认参数env即为当前触发组件的实例;若传递了参数,如onClickHandler2,则参数安顺序排列,env为***一个参数。

触发原生组件事件

用户可通过手动操作触发事件,如点击事件等,除此之外,也可以在代码中通过$emitElement()完成事件的动态触发,类似上文自定义组件中的$emit()方法。

$emitElement(evtName, evtDetail, id)

可以触发指定组件id的事件,通过evt.detail获取传递的参数;该方法仅用于原生组件,对自定义组件无效。

示例如下:

<template 
<div class="tutorial-page" 
<text onclick="emitElement">触发组件节点的事件:click</text>  
<text id="elNode1" item-flag="{{ argName + 1 }}" onclick = "onClickHandler">组件节点1</text>  
<text id="elNode2" item-flag="{{ argName + 2 }}" onclick = "onClickHandler2('参数1', argName)">组件节点2</text>  
</div>  
</template
 
<style lang="less" 
.tutorial-page {  
flex-direction: column;  
 
</style> 
 
<script>  
export default {  
data () {  
return {  
argName: '动态参数'  
 
}, 
 
onClickHandler (evt) {  
// 事件类型,参数详情  
console.info(`触发事件:类型:${evt.type}, 详情: ${JSON.stringify(evt.detail)}`);  
if (evt.target) {  
console.info(`触发事件:节点:${evt.target.id}, ${evt.target.attr.itemFlag}`)  
 
}, 
 
onClickHandler2 (arg1, arg2, evt) {  
// 事件类型,事件参数,target  
console.info(`触发事件:类型:${evt.type}, 参数: ${arg1}, ${arg2}`);  
}, 
 
emitElement () {  
// 注意:通过此类方式的事件不会携带target属性,开发者可以通过detail参数实现  
this.$emitElement('click', { params: '参数内容' }, 'elNode1' 
 
 
</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.
  • 1.

解释一下

Click事件可通过用户点击操作触发,也可通过$emitElement触发。

自定义组件

上文曾提到原生组件,通常原生组件是我们系统中最基础的组件,然而我们在做一个稍微复杂的页面时,如果每个页面都只用原生组件搭建,那这样的代码的可维护性会差很多。打个比方,就好比一个人口众多的国家,没有省、市、县这些单位,而是只以个人为单位,难以想象这个国家的管理将有多难。道理类似,自定义组件,我们可以根据具体的业务逻辑,把页面按照功能拆成多个模块,每个模块负责其中的一个功能部分,***页面将由这些模块组合搭建起来,让代码结构更加清晰,易于维护。

自定义组件是开发者编写的组件,使用起来和Native原生组件一样,最终按照组件的<template>来渲染;同时开发起来又和页面一样,拥有ViewModel实现对数据、事件、方法的管理,这么来看,页面也是一种特殊的自定义组件,无需引入即可使用,同时服务于整个页面。

编写自定义组件

示例如下:

<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> 
  • 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.

两点注意

一是自定义组件比页面组件的不同之处在于多了一个props属性,用于声明该组件可接受的外部数据传递;props是一个数组,数组中每个元素是暴露的属性。

二是如果属性名称使用驼峰定义,如:prop2Object,那么在外部传递数据时请使用-连接,如:prop2-object

引入自定义组件

引入自定义组件的方式和我们平时常用的方式不同,我们平时通常会用require或import的方式引入组件,而在快应用框架中,需要使用<import>标签来引入。

示例如下:

<import name="comp-part1" src="./part1"></import>  
  • 1.
  • 1.
  • 1.

<import>标签中的的src属性指定自定义组件的地址,name属性指定在<template>组件中引用该组件时使用的标签名称

最终页面定义与引入方式如下:

<import name="comp-part1" src="./part1"></import
 
<template> 
 
<div class="tutorial-page"
 
<text class="tutorial-title">页面组件:</text> 
 
<text>{{ data1 }}</text> 
 
<text>{{ data2.name }}</text> 
 
<text onclick="evtType1Emit">触发$broadcast()</text> 
 
<comp-part1 prop1="{{data1}}" prop2-object="{{data2}}" onevt-type3="evtTypeHandler"></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: { 
 
data1: '传递字符串'
 
data2: { 
 
name: '传递对象' 
 

 
}, 
 
onInit () { 
 
this.$page.setTitleBar({ text: '父子组件通信' }) 
 
this.$on('evtType2'this.evtTypeHandler) 
 
}, 
 
evtTypeHandler (evt) { 
 
console.info(`父组件:事件响应: `, evt.type, evt.detail) 
 
// 结束事件传递 
 
// evt.stop() 
 
}, 
 
evtType1Emit () { 
 
this.$broadcast('evtType1', { params: '额外参数' }) 
 

 

 
</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.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 1.

解释一下

上面的代码中有几点需要说明:

1 在comp-part1标签中,我们看到这样一个属性,onevt-type3="evtTypeHandler",这是指,在该节点上绑定了名为evtType3的方法,被触发后,执行evtTypeHandler的函数,在下文的‘父子之间组件事件传递’中,会看到如何触发该方法。

2 代码中的evtType1Emit方法,该方法通过调用$broadcast方法,触发了名为'evtType1'的事件,并传递了params参数,'evtType1'事件也可以在下文‘父子组件之间事件传递’中看到。

传递数据与数据改造

如上面所述,父组件向子组件传递数据,通过在子组件的props属性中声明对外暴露的属性名称,然后在组件引用标签上声明传递的父组件数据。

如果你需要在子组件中对数据进行改造,但又不想改动父组件数据时,可以使用$watch()来满足需求。如果是监听对象中的属性,参数请使用.分割,如:$watch(xxx.xxx.xxx, methodName)

示例如下:

<script>  
  
// 子组件  
  
export default {  
  
props: [  
  
'prop1',  
  
'prop2Object'  
  
],  
  
data () {  
  
return {  
  
upperProp1: this.prop1  
  
}  
  
},  
  
onInit () {  
  
console.info(`外部传递的数据:`, this.prop1, this.prop2Object)  
  
// 监听数据变化  
  
this.$watch('prop1''watchPropsChange')  
  
this.$watch('prop2Object.name''watchPropsChange')  
  
},  
  
/**  
  
* 监听数据变化,你可以对数据处理后,设置值到data上  
  
* @param newV  
  
* @param oldV  
  
*/  
  
watchPropsChange (newV, oldV) {  
  
console.info(`监听数据变化:`, newV, oldV)  
  
this.upperProp1 = newV && newV.toUpperCase()  
  
}  
  
}  
  
</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.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.

解释一下

上面是子组件的代码,我们看到data中定义了upperProp1,同时也看到watchPropsChange方法中,有两个参数,一个是newV,指变化后的属性值,oldV指原先的属性值,将newV赋值给upperProp1,这样在子组件中对数据upperProp1进行改造,就不会改动父组件原先的数据。

父子组件之间的事件传递

当子组件对数据进行改造后,把最终数据交给父组件甚至往上,往往有两种办法

1、父组件传递的数据本身就是对象,子组件直接修改的就是这个对象中的属性;那么父组件同样也就拿到了最终数据

2、子组件在data中保存了一份内部数据,需要交给父组件:子组件通过$dispatch()完成事件触发,父组件通过$on()绑定事件并响应,如:evtType2;

类似于2,子组件在data中保存了一份内部数据,需要交给父组件:子组件通过$emit()触发在节点上绑定的事件来执行父组件的方法,如:evtType3;

示例如下:

<script>  
  
// 子组件  
  
export default {  
  
props: [  
  
'prop1',  
  
'prop2Object'  
  
],  
  
data () {  
  
return {  
  
upperProp1: this.prop1  
  
}  
  
},  
  
onInit () {  
  
console.info(`外部传递的数据:`, this.prop1, this.prop2Object)  
  
// 绑定VM的自定义事件  
  
this.$on('evtType1'this.evtTypeHandler)  
  
// 这里我认为官网的代码示例存在问题,因此注释掉了,此处应该将其移至父组件的onInit方法中。  
  
//this.$on('evtType2', this.evtTypeHandler)  
  
},  
  
evtTypeHandler (evt) {  
  
console.info(`子组件:事件响应: `, evt.type, evt.detail)  
  
// 结束事件传递  
  
// evt.stop()  
  
},  
  
evtType2Emit () {  
  
this.$dispatch('evtType2', { params: '额外参数' })  
  
},  
  
evtType3Emit () {  
  
this.$emit('evtType3', { params: '额外参数' })  
  
}  
  
}  
  
</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.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.

解释一下

在上文我已做了如下说明

1 在父组件的comp-part1标签中,我们看到这样一个属性,onevt-type3 = "evtTypeHandler",这是指,在该节点上绑定了名为evtType3的方法,如果子组件中evtType3Emit调用执行,则会执行父组件中的evtTypeHandler的函数, 从而完成子组件与父组件的通信。

2 父组件中的evtType1Emit方法,该方法通过调用$broadcast方法,触发了名为'evtType1'的事件,并传递了params参数,'evtType1'事件则注册在子组件的onInit方法中,从而完成父组件与子组件的通信。

所以,框架向开发者提供了双向的事件传递。

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

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

兄弟组件之间的通信

传统的兄弟等非父子组件之间通信,是通过观察者模型来完成。观察者模式的作用是当一个对象的状态发生变化时,能够自动通知其他关联对象,自动刷新对象状态。

开发者可以自己写一个Pub/Sub模型实现通信解耦;不过本文并不详细介绍如何通过观察者模式来实现组件间通信,这个题目够另写一篇文章了。

其实,在业务逻辑相对简单的情况下,我们可以使用ViewModel本身的事件绑定来处理。兄弟组件的相同点是,他们拥有相同的父组件,所以,父组件将是兄弟组件通信的桥梁,可以在以下代码中看到这个过程。

示例如下:

子组件定义了Sub端的逻辑处理,有processMessage()、customEventInVm2(),后者同使用$on效果一致

<template>  
  
<div class="tutorial-page">  
  
<text class="tutorial-title">自定义组件2:</text>  
  
<text>处理消息:{{msg}}</text>  
  
<text>事件内容:{{eventDetail}}</text>  
  
</div>  
  
</template>  
  
<style lang="less">  
  
</style>  
  
<script>  
  
// 子组件: part2  
  
export default {  
  
props: [  
  
],  
  
data () {  
  
return {  
  
msg: null,  
  
eventDetail: null  
  
}  
  
},  
  
processMessage (msg) {  
  
const now = (new Date).toISOString()  
  
this.msg = `${now}: ${msg}`  
  
},  
  
/**  
  
* 通过events对象:绑定事件,和on效果一致  
  
*/  
  
events: {  
  
customEventInVm2 (evt) {  
  
const now = (new Date).toISOString()  
  
this.eventDetail = `${now}: ${evt.detail}`  
  
}  
  
}  
  
}  
  
</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.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.

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

<template>  
  
<div class="tutorial-page">  
  
<!-- 兄弟VM通信 -->  
  
<comp-part2 id="sibling1"></comp-part2>  
  
<comp-part3 id="sibling2"></comp-part3>  
  
</div>  
  
</template>  
  
<style lang="less">  
  
</style>  
  
<script>  
  
// 父组件  
  
export default {  
  
onReady () {  
  
this.establishRef()  
  
},  
  
/**  
  
* 建立相互VM的引用,父组件将两个兄弟组件联系了起来  
  
*/  
  
establishRef () {  
  
const siblingVm1 = this.$vm('sibling1')  
  
const siblingVm2 = this.$vm('sibling2')  
  
siblingVm1.parentVm = this  
  
siblingVm1.nextVm = siblingVm2  
  
siblingVm2.parentVm = this  
  
siblingVm2.previousVm = siblingVm1  
  
}  
  
}  
  
</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.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.

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

<template>  
  
<div class="tutorial-page">  
  
<text class="tutorial-title">自定义组件3:</text>  
  
<text onclick="sendMesssage">点击发送消息</text>  
  
</div>  
  
</template>  
  
<style lang="less">  
  
</style>  
  
<script>  
  
// 子组件: part3  
  
export default {  
  
sendMesssage () {  
  
if (this.previousVm) {  
  
// Way1. 调用方法  
  
this.previousVm.processMessage('兄弟之间通信的消息内容')  
  
// Way2. 触发事件  
  
this.previousVm.$emit('customEventInVm2''兄弟之间通信的消息内容')  
  
}  
  
}  
  
}  
  
</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.

解释一下

通过上面的例子,我们可以看到,comp-part2和 comp-part3在父组件中通过nextVm和previousVm建立了‘兄弟关系’,基于此,它们之间可以直接调用对方的方法(如processMessage),或会通过$emit方法触发对方监听的事件'customEventInVm2'

结尾

本文对快应用开发中的事件监听以及触发方式做了介绍,通过学习我们能够更好的分离业务逻辑,减少方法响应上的耦合。另外,通过掌握自定义组件的开发,会让我们的项目结构更加明朗,更易于维护;同时了解父子、兄弟组件之间的数据通信,更是完成好快应用开发的必要条件。当然,本文多数素材来源于官方文档中的示例,但对其中模糊之处做了相应解释和补充,希望能够给读者些许帮助。如有不足之处,欢迎指正。