当前位置: 首页 > 科技观察

鸿蒙JS UI 组件通信总结及任意组件通信

时间:2023-03-19 15:35:35 科技观察

HarmonyJSUI组件通信和任意组件通信总结在组件之间传递数据或执行相关业务逻辑。对于鸿蒙应用组件,下面会实现几个组件间通信方法的代码实现,包括任意组件通信的自定义实现的实现。首先我们准备几个组件parent组件,current组件,child1组件,child2组件,其中parent和current是父子组件关系,curren和child1/child2是父子组件关系,child1和child2是兄弟组件关系,parentchild1/child2是跨层次组件的关系。common.css.title{font-size:20px;text-align:left;padding-bottom:5px;line-height:20px;}.div-button{flex-direction:row;}.div-button.button{margin:5px;}1.parent组parent.hmlparent-num:{{num}}parent-info-str:{{info.str}}

parent.jsexportdefault{data:{num:0,info:{str:'parentStr'}}}parent.css@import'../../../common/css/common.css';.container{display:flex;flex:1;flex-direction:column;width:100%;padding:10px;background-color:aqua;}2.current组件current.hmlcurrent-title:{{title}}current-num:{{num}}current-info-str:{{info.str}}
current.jsexportdefault{props:{title:{default:'current-title',}},data:{num:0,info:{str:'currentStr'}},//修改父组件的num和infochangeParent(){console.log('**start**********************');console.log('currenchangeparent');letparent=this.$parent();letnum=parent.num+1;parent.nu??m=num;letinfo={str:'currenchangeparent'};//current.info=info;parent.info.str='currenchangeparent';console.log('num:');console.log(num);console.log('info:');console.log(JSON.stringify(info));console.log('**end*************************');},//修改child1组的num和infochangeChild1(){console.log('**start**********************');console.log('currentchangechild1');letchild1=this.$child('child1');letnum=child1.num+1;child1.num=num;letinfo={str:'currentchangechild1'};child1.info=info;console.log('num:');console.log(num);console.log('info:');console.log(JSON.stringify(info));console.log('**end************************');},//修改child2组的num和infochangeChild2(){console.log('**开始************************');console.log('currenchangechild2');letchild2=this.$child('child2');letnum=child2.nu??m+1;child2.num=num;letinfo={str:'currenchangechild2'};child2.info=info;console.log('num:');console.log(num);console.log('info:');console.log(JSON.stringify(info));console.log('**end************************');}}current.css@import'../../../common/css/common.css';.container{display:flex;flex:1;flex-direction:column;width:100%;padding:10px;background-color:aquamarine;border:1pxsolid#333333;}3.child1组件child1.hmlchild1-num:{{num}}child1-info-str:{{info.str}}
child1.jsexportdefault{data:{num:0,info:{str:'child1Str'}}}child1.css@import'../../../common/css/common.css';.container{display:flex;flex-direction:column;width:100%;padding:10px;background-color:bisque;border:1pxsolid#333333;min-height:200px;}4.child2组文件child2.hmlchild2-num:{{num}}child2-info-str:{{info.str}}child2.jsexportdefault{data:{num:0,info:{str:'child2Str'}}}child2.css@import'../../../common/css/common.css';.container{display:flex;flex-direction:column;width:100%;padding:10px;background-color:beige;border:1pxsolid#333333;margin-top:10px;min-height:200px;}最终预览结果如下:父子关系通信parent和current是父子组件关系,在current.jspropstitle=''current-title",在parent.hml中使用当前组件时,传入title="parent"时,当前组件显示parentCurren和child1/child2是父子组件关系。在当前组件中,有三个按钮分别是改变父级、改变子级1和改变子级2。在curren组件中,点击changeparent按钮触发changeParent方法,点击changechild1按钮触发changeChild1方法。点击更改child1按钮会触发changeChild1方法,该方法会更改对应组件中的数据,如下:点击更改parent点击更改child1点击更改child2在changeParent方法中,使用this.$parent()方法获取父组件的ViewModel,从而可以访问和更改父组件的数据在changeChild1和changeChild2中,通过this.$child(id)方法获取child1/child2组件的ViewModel,使得child1/child2组件的数据可以被访问和改变除了使用this.$parent方法之外还可以使用自定义事件让子组件调用父组件方法向父组件传值。父组件在引用当前组件时绑定事件,调用当前组件中的this.$emit方法触发绑定的self。定义事件。parent.hmlparent.jscurrent.js总结一下,父子组件之间的通信方式大概有以下几种:props:用于父组件向子组件传输数据$emit:用于组件向子组件传输数据父组件或调用父组件的方法$parent:用于获取父组件ViewModel,以便修改父组件的数据父组件的方法调用$child:用于获取子组件的ViewModel组件从而修改子组件的数据并调用子组件的方法组件的通信方法,对于兄弟组件和跨级组件,可以使用以上方法的组合来实现非父组件之间的通信-子组件,但是如果组件之间的嵌套比较复杂,嵌套层次比较多的情况下,使用combinati显然不方便以上方法之一。这里,我们尝试实现一种类似于vuebus的全局通信方式,实现任意组件之间的通信。JSAPI中app.js文件中定义的数据可以通过this.app.app.def获取。根据这个特点和观察者模式,设计了一种可以全局订阅响应的通信模式。首先我们定义evnetBus.js文件,在里面定义订阅、发布、取消订阅的相关方法:eventBus.jsconstBus={//发布事件集合$events:{},/***发布事件方法*type:stringString*fun:函数绑定的方法**/$on(type,fun){},/***触发事件方法*type:string释放事件string*args:传递参数**/$emit(type,...args){},/***注销事件方法*type:stringstring*fun:string|function事件释放或原函数释放时的返回值**/$off(type,fun){}}导出默认总线;其中,我们定义了存储绑定事件的$events对象,绑定事件的$on方法,触发事件的$emit方法,注销事件的$off方法,completeeventBus。js如下eventBus.jsconstBus={//发布事件集合$events:{},/***发布事件方法*type:stringstring*fun:函数绑定方法**/$on(type,fun){letres="";if(type&&typeoftype=="string"&&fun&& typeoffun =="function"){letevents=this.$events[type];if(events){letindex=events.findIndex(null);if(index>-1){res=`${String(index)}${type}`;events[index]=fun;}else{events.push(fun);}}else{this.$events[type]=[fun];res=`0${type}`;}}returnres;},/***触发事件方法*type:string事件发布字符串*args:传递参数**/$发出(类型,...args){if(类型&&typeoftype="string"){letevents=this.$events[type];if(events){events.forEach(fun=>{if(fun&& typeoffun =="function"){fun(...args);}});}}},/***注销事件方法*type:string*fun:string|function释放事件或发布原函数时的返回值**/$off(type,fun){if(type&&typeoftype=="string"&&fun){letevents=this.$events[type];if(events){if(typeoffun=="string"){letindexStr=fun.replace(type,'');letindex=parseInt(indexStr);events[index]=null;}if(typeoffun=="function"){events.forEach(item=>{if(item==fun){item=null;}});}}}}}exportdefaultBus;使用方法如下:首先在app.js中引入eventBus:在父组件的onInit方法中绑定事件,通过绑定的事件改变父组件的值:然后我们修改child1组件,添加触发总线事件的按钮:触发该方法时,我们传入了自定义参数数据“123456789”。点击按钮后,会触发我们在父组件中绑定的方法更改父组件的数据,同时也会从子组件接收到数据“123456789”,这里实现了跨级组件间的通信。该方法可有效用于任意组件间的事件触发和传值,限于篇幅不再展示。最后,我们必须在组件销毁时注销。对于事件,我们定义一个注销事件的按钮,并绑定注销事件:我们在$on绑定事件的时候可以得到一个返回值,这个值也可以用于事件注销,这里就不演示了这里,有兴趣的可以下去试试。以上就是使用观察者模式实现了一个简单版本的事件总线机制,可以在任意组件之间进行通信,基本功能都可以实现。还有一些不足需要提醒一下:1、首先this在使用app.$def时必须依赖鸿蒙JSAPIthis.$app.$def每次获取eventBus对象都要用到这个方法。2.注册绑定事件后,一定要记得在当前组件销毁时取消绑定事件,否则可能会造成内存泄漏。3、注销事件有两种方式,需要先了解注销事件的原理,才能熟练使用。文章相关附件可点击下方原文链接下载TestApp.rar更多内容请访问:与华为官方共建的鸿蒙技术社区https://harmonyos.51cto.com