当前位置: 首页 > news >正文

HarmonyOS开发实战( Beta5.0)自定义装饰器实践规范

介绍

本示例介绍通过自定义装饰器在自定义组件中自动添加inspector (布局回调)方法并进行调用。

效果图预览

不涉及

使用说明

  1. 在自定义组件上添加自定义装饰器@CallbackObserver,并根据参数设置对应的方法名和需要绑定的组件的ID。
  2. 编译工程,可以根据自定义装饰器生成方法并调用。
具体使用方法
  1. 在工程的hvigor-config.json5中配置插件。

    {..."dependencies": {..."@app/ets-decoration": "file:../libs/autobuilddecoration-1.0.0.tgz"}
    }
    
  2. 在需要使用自定义装饰器的模块的hvigorfile.ts中添加依赖和文件路径。

    import { harTasks } from '@ohos/hvigor-ohos-plugin';
    import { DecorationPluginConfig, etsDecorationPlugin } from '@app/ets-decoration';const config: PluginConfig = {scanFiles: [""],
    }
    export default {system: harTasks, /* Built-in plugin of Hvigor. It cannot be modified. */plugins: [etsDecorationPlugin(config)]         /* Custom plugin to extend the functionality of Hvigor. */
    }
    
  3. 在自定义组件上添加自定义装饰器@CallbackObserver,并设置对应的方法名和组件ID。

    @CallbackObserver({onDraw: 'onDraw',onLayout: 'onLayout',offDraw: 'offDraw',offLayout: 'offLayout',bindId: 'text'
    })
    @Component
    export struct MainPage {build() {Column() {Text("Hello World").id('text')}}
    }
    
  4. 编译工程,即可生成对应的方法和调用代码。

实现思路

  1. 在ArkTS侧实现自定义装饰器,并配置需要的参数。

    // 自定义装饰器
    export function AutoAddInspector(param: InspectorParam) {return Object;
    }
    // 装饰器参数
    export interface InspectorParam {// inspector中onDraw需要配置的回调方法onDraw?: string;// inspector中onLayout需要配置的回调方法onLayout?: string;// inspector中offDraw需要配置的回调方法offDraw?: string;// inspector中offLayout需要配置的回调方法offLayout?: string;// 需要绑定的组件的IDbindId?:string;
    }
    
  2. 通过hvigorfile.ts中的配置,将使用自定义装饰器的文件路径传到插件中。

    import { DecorationPluginConfig, etsDecorationPlugin } from '@app/ets-decoration-generator';const config: DecorationPluginConfig = {// 配置自定义装饰器的文件路径scanFiles: ["src/main/ets/components/MainPage"],
    }export default {system: harTasks,  /* Built-in plugin of Hvigor. It cannot be modified. */plugins:[etsDecorationPlugin(config)]         /* Custom plugin to extend the functionality of Hvigor. */
    }
    
  3. 将传入的文件解析为TypeScript抽象语法树,得到所有的节点信息。详细代码可参考Index.ts。

    start() {// 读取文件const sourceCode = readFileSync(this.sourcePath, "utf-8");// 解析文件,生成节点树信息const sourceFile = ts.createSourceFile(this.sourcePath, sourceCode, ts.ScriptTarget.ES2021, false);// 遍历节点信息ts.forEachChild(sourceFile, (node: ts.Node) => {// 解析节点console.log(JSON.stringify(node));this.resolveNode(node);});
    }
    
  4. 遍历节点,获取自定义装饰器中配置的参数,将方法名存入到列表中。

    // 解析装饰器
    resolveDecoration(node: ts.Node) {...if ((propertie.name as ts.StringLiteral).text !== 'bindId') {// 如果参数名不是“bindId”,则放入需要创建的方法列表中let methodInfo: MethodInfo = new MethodInfo();methodInfo.name = (propertie.name as ts.StringLiteral).text;methodInfo.value = (propertie.initializer as ts.StringLiteral).text;decoratorInfo.methods.push(methodInfo);this.methodArray.push((propertie.initializer as ts.StringLiteral).text);} else {// 如果参数名是“buildId”,则设置到对应的变量中decoratorInfo.bindId = (propertie.initializer as ts.StringLiteral).text;}...this.decorationInfos.push(decoratorInfo);...      
    }
    
  5. 遍历节点,记录aboutToAppear()方法的位置,并和第4步中存储的列表进行比较,过滤已经存在的方法,防止生成同名方法。

    // 解析装饰器装饰的自定义组件(从“{”到“}”)
    resolveBlock(node: ts.Node) {...// 自定义组件中已经存在的方法列表const methodNameArray: string[] = [];statements.forEach((statement: ts.Statement) => {...const identifier = callExpression.expression as Identifier;methodNameArray.push(identifier.escapedText.toString());// 查找是否已经存在aboutToAppear方法if (identifier.escapedText === 'aboutToAppear') {this.aboutToAppearExist = true;this.positionOfAboutToAppear = statement.pos;}...})// 过滤已经存在的装饰器中的方法const temp = this.methodArray.filter((value: string, index: number) => {return !methodNameArray.includes(value);})this.methodArray = temp;// 记录自定义组件的结束位置this.positionOfBlockEnd = node.end;}
    }
    
  6. 根据解析结果,生成方法代码和相关调用代码,并写入原文件中。

    function pluginExec(config: DecorationPluginConfig) {...// 开始解析文件analyzer.start();// 如果解析的文件中存在装饰器,则将结果保存到列表中if (analyzer.routerAnnotationExisted) {// 如果有需要创建的方法if (analyzer.methodArray.length > 0) {...// 装饰器中如果设置了bindId,则添加listener变量,并在aboutToAppear中调用监听方法// aboutToAppear方法是否已存在 if (analyzer.aboutToAppearExist) {// 如果已经存在aboutToAppear,则根据aboutToAppear方法的位置拆分结构体,并将需要生成的代码添加到对应的位置...} else {// 如果不存在aboutToAppear方法,则创建aboutToAppear方法,并添加调用代码...}// 根据模板创建装饰器中配置的方法...// 将生成的代码写入文件中writeFileSync(sourcePath, fileContent, { encoding: "utf8" })}}...
    }
    

工程结构&模块类型

customdecoration                               // har类型
|---components
|   |---CallbackObserver.ets                   // 自定义装饰器
|   |---MainPage.ets                           // UI页面

最后

小编在之前的鸿蒙系统扫盲中,有很多朋友给我留言,不同的角度的问了一些问题,我明显感觉到一点,那就是许多人参与鸿蒙开发,但是又不知道从哪里下手,因为体系杂乱无章,教授的人也多,无从选择。有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)路线、视频、文档用来跟着学习是非常有必要的。

如果你是一名有经验的资深Android移动开发、Java开发、前端开发、对鸿蒙感兴趣以及转行人员

鸿蒙 NEXT 全栈开发学习笔记 希望这一份鸿蒙学习文档能够给大家带来帮助~


 鸿蒙(HarmonyOS NEXT)最新学习路线

该路线图包含基础技能、就业必备技能、多媒体技术、六大电商APP、进阶高级技能、实战就业级设备开发,不仅补充了华为官网未涉及的解决方案

路线图适合人群:

IT开发人员:想要拓展职业边界
零基础小白:鸿蒙爱好者,希望从0到1学习,增加一项技能。
技术提升/进阶跳槽:发展瓶颈期,提升职场竞争力,快速掌握鸿蒙技术

2.视频教程+学习PDF文档

(鸿蒙语法ArkTS、TypeScript、ArkUI教程……)

 纯血版鸿蒙全套学习文档(面试、文档、全套视频等)

                   

鸿蒙APP开发必备

​​

总结

参与鸿蒙开发,你要先认清适合你的方向,如果是想从事鸿蒙应用开发方向的话,可以参考本文的学习路径,简单来说就是:为了确保高效学习,建议规划清晰的学习路线

相关文章:

  • 掌握Python自动化:探索keymousego库的无限可能!
  • Oracle OCP认证值得考吗? 需要门槛吗?
  • 【软件设计师真题】下午题第四大题---算法设计
  • 高基数 GroupBy 在 SLS SQL 中的查询加速
  • linux-进程管理-守护进程(Daemon)
  • 讯飞语音转文字怎么样?试试这4款工具吧!
  • 动态规划解决LCS问题
  • ElasticSearch底层原理解析
  • ESXI8.0 vsphere vcenter 多网卡多网段配置
  • OpenHarmony开发实战:动画样式(JS),2024年最新自学HarmonyOS鸿蒙
  • 三菱伺服电机抱闸(刹车)的用法
  • 研1日记9
  • 开源FormCreate低代码表单组件的配置项和事件的详解
  • 【二】TDEngine快速入门
  • 深入理解FastAPI的response_model:自动化数据验证与文档生成
  • 「前端早读君006」移动开发必备:那些玩转H5的小技巧
  • eclipse的离线汉化
  • idea + plantuml 画流程图
  • JavaScript中的对象个人分享
  • js继承的实现方法
  • Laravel 菜鸟晋级之路
  • mysql外键的使用
  • php中curl和soap方式请求服务超时问题
  • Python中eval与exec的使用及区别
  • Stream流与Lambda表达式(三) 静态工厂类Collectors
  • Vim 折腾记
  • Vue 动态创建 component
  • 从零开始在ubuntu上搭建node开发环境
  • 动态魔术使用DBMS_SQL
  • 更好理解的面向对象的Javascript 1 —— 动态类型和多态
  • 看图轻松理解数据结构与算法系列(基于数组的栈)
  • 聊聊hikari连接池的leakDetectionThreshold
  • 融云开发漫谈:你是否了解Go语言并发编程的第一要义?
  • 如何学习JavaEE,项目又该如何做?
  • 深入浅出Node.js
  • 数据仓库的几种建模方法
  • 用element的upload组件实现多图片上传和压缩
  • No resource identifier found for attribute,RxJava之zip操作符
  • 宾利慕尚创始人典藏版国内首秀,2025年前实现全系车型电动化 | 2019上海车展 ...
  • ​【已解决】npm install​卡主不动的情况
  • ​DB-Engines 11月数据库排名:PostgreSQL坐稳同期涨幅榜冠军宝座
  • ​ssh-keyscan命令--Linux命令应用大词典729个命令解读
  • ​经​纬​恒​润​二​面​​三​七​互​娱​一​面​​元​象​二​面​
  • ​你们这样子,耽误我的工作进度怎么办?
  • ‌移动管家手机智能控制汽车系统
  • #pragma once与条件编译
  • (k8s中)docker netty OOM问题记录
  • (react踩过的坑)antd 如何同时获取一个select 的value和 label值
  • (二)WCF的Binding模型
  • (论文阅读23/100)Hierarchical Convolutional Features for Visual Tracking
  • (强烈推荐)移动端音视频从零到上手(上)
  • (四)js前端开发中设计模式之工厂方法模式
  • (原创)攻击方式学习之(4) - 拒绝服务(DOS/DDOS/DRDOS)
  • (转)Google的Objective-C编码规范
  • (转)拼包函数及网络封包的异常处理(含代码)