鸿蒙应用开发(HarmonyOS)自定义装饰器场景

打印 上一主题 下一主题

主题 977|帖子 977|积分 2933

  鸿蒙NEXT开发实战往期必看文章:
一分钟相识”纯血版!鸿蒙HarmonyOS Next应用开发!
“非常具体的” 鸿蒙HarmonyOS Next应用开发学习路线!(从零根本入门到精通)
HarmonyOS NEXT应用开发案例实践总联合(持续更新......)
HarmonyOS NEXT应用开发性能优化实践总结(持续更新......)

先容

本示例先容通过自定义装饰器在自定义组件中自动添加inspector (布局回调)方法并进行调用。
效果图预览

不涉及
使用说明


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


  • 在工程的hvigor-config.json5中配置插件。
    1. {
    2.   ...
    3.   "dependencies": {
    4.     ...
    5.     "@app/ets-decoration": "file:../libs/autobuilddecoration-1.0.0.tgz"
    6.   }
    7. }
    复制代码
  • 在需要使用自定义装饰器的模块的hvigorfile.ts中添加依赖和文件路径。
    1. import { harTasks } from '@ohos/hvigor-ohos-plugin';
    2. import { DecorationPluginConfig, etsDecorationPlugin } from '@app/ets-decoration';
    3. const config: PluginConfig = {
    4.   scanFiles: [""],
    5. }
    6. export default {
    7.   system: harTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
    8.   plugins: [etsDecorationPlugin(config)]         /* Custom plugin to extend the functionality of Hvigor. */
    9. }
    复制代码
  • 在自定义组件上添加自定义装饰器@CallbackObserver,并设置对应的方法名和组件ID。
    1. @CallbackObserver({
    2. onDraw: 'onDraw',
    3. onLayout: 'onLayout',
    4. offDraw: 'offDraw',
    5. offLayout: 'offLayout',
    6. bindId: 'text'
    7. })
    8. @Component
    9. export struct MainPage {
    10. build() {
    11.    Column() {
    12.      Text("Hello World")
    13.        .id('text')
    14.    }
    15. }
    16. }
    复制代码
  • 编译工程,即可生成对应的方法和调用代码。
实现思绪


  • 在ArkTS侧实现自定义装饰器,并配置需要的参数。
    1. // 自定义装饰器
    2. export function AutoAddInspector(param: InspectorParam) {
    3.   return Object;
    4. }
    5. // 装饰器参数
    6. export interface InspectorParam {
    7.   // inspector中onDraw需要配置的回调方法
    8.   onDraw?: string;
    9.   // inspector中onLayout需要配置的回调方法
    10.   onLayout?: string;
    11.   // inspector中offDraw需要配置的回调方法
    12.   offDraw?: string;
    13.   // inspector中offLayout需要配置的回调方法
    14.   offLayout?: string;
    15.   // 需要绑定的组件的ID
    16.   bindId?:string;
    17. }
    复制代码
  • 通过hvigorfile.ts中的配置,将使用自定义装饰器的文件路径传到插件中。
    1. import { DecorationPluginConfig, etsDecorationPlugin } from '@app/ets-decoration-generator';
    2. const config: DecorationPluginConfig = {
    3.         // 配置自定义装饰器的文件路径
    4.     scanFiles: ["src/main/ets/components/MainPage"],
    5. }
    6. export default {
    7.     system: harTasks,  /* Built-in plugin of Hvigor. It cannot be modified. */
    8.     plugins:[etsDecorationPlugin(config)]         /* Custom plugin to extend the functionality of Hvigor. */
    9. }
    复制代码
  • 将传入的文件解析为TypeScript抽象语法树,得到所有的节点信息。具体代码可参考Index.ts。
    1. start() {
    2.   // 读取文件
    3.   const sourceCode = readFileSync(this.sourcePath, "utf-8");
    4.   // 解析文件,生成节点树信息
    5.   const sourceFile = ts.createSourceFile(this.sourcePath, sourceCode, ts.ScriptTarget.ES2021, false);
    6.   // 遍历节点信息
    7.   ts.forEachChild(sourceFile, (node: ts.Node) => {
    8.     // 解析节点
    9.     console.log(JSON.stringify(node));
    10.     this.resolveNode(node);
    11.   });
    12. }
    复制代码
  • 遍历节点,获取自定义装饰器中配置的参数,将方法名存入到列表中。
    1. // 解析装饰器
    2. resolveDecoration(node: ts.Node) {
    3.   ...
    4.   if ((propertie.name as ts.StringLiteral).text !== 'bindId') {
    5.     // 如果参数名不是“bindId”,则放入需要创建的方法列表中
    6.     let methodInfo: MethodInfo = new MethodInfo();
    7.     methodInfo.name = (propertie.name as ts.StringLiteral).text;
    8.     methodInfo.value = (propertie.initializer as ts.StringLiteral).text;
    9.     decoratorInfo.methods.push(methodInfo);
    10.     this.methodArray.push((propertie.initializer as ts.StringLiteral).text);
    11.   } else {
    12.     // 如果参数名是“buildId”,则设置到对应的变量中
    13.     decoratorInfo.bindId = (propertie.initializer as ts.StringLiteral).text;
    14.   }
    15.   ...
    16.   this.decorationInfos.push(decoratorInfo);
    17.   ...      
    18. }
    复制代码
  • 遍历节点,记录aboutToAppear()方法的位置,并和第4步中存储的列表进行比较,过滤已经存在的方法,防止生成同名方法。
    1. // 解析装饰器装饰的自定义组件(从“{”到“}”)
    2. resolveBlock(node: ts.Node) {
    3.   ...
    4.   // 自定义组件中已经存在的方法列表
    5.   const methodNameArray: string[] = [];
    6.   statements.forEach((statement: ts.Statement) => {
    7.     ...
    8.     const identifier = callExpression.expression as Identifier;
    9.     methodNameArray.push(identifier.escapedText.toString());
    10.     // 查找是否已经存在aboutToAppear方法
    11.     if (identifier.escapedText === 'aboutToAppear') {
    12.       this.aboutToAppearExist = true;
    13.       this.positionOfAboutToAppear = statement.pos;
    14.     }
    15.     ...
    16.   })
    17.   // 过滤已经存在的装饰器中的方法
    18.   const temp = this.methodArray.filter((value: string, index: number) => {
    19.     return !methodNameArray.includes(value);
    20.   })
    21.   this.methodArray = temp;
    22.   // 记录自定义组件的结束位置
    23.   this.positionOfBlockEnd = node.end;
    24.   }
    25. }
    复制代码
  • 根据解析效果,生成方法代码和相关调用代码,并写入原文件中。
    1. function pluginExec(config: DecorationPluginConfig) {
    2.   ...
    3.   // 开始解析文件
    4.   analyzer.start();
    5.   // 如果解析的文件中存在装饰器,则将结果保存到列表中
    6.   if (analyzer.routerAnnotationExisted) {
    7.     // 如果有需要创建的方法
    8.     if (analyzer.methodArray.length > 0) {
    9.       ...
    10.       // 装饰器中如果设置了bindId,则添加listener变量,并在aboutToAppear中调用监听方法
    11.       // aboutToAppear方法是否已存在
    12.       if (analyzer.aboutToAppearExist) {
    13.         // 如果已经存在aboutToAppear,则根据aboutToAppear方法的位置拆分结构体,并将需要生成的代码添加到对应的位置
    14.         ...
    15.       } else {
    16.         // 如果不存在aboutToAppear方法,则创建aboutToAppear方法,并添加调用代码
    17.         ...
    18.       }
    19.       // 根据模板创建装饰器中配置的方法
    20.       ...
    21.       // 将生成的代码写入文件中
    22.       writeFileSync(sourcePath, fileContent, { encoding: "utf8" })
    23.     }
    24.   }
    25.   ...
    26. }
    复制代码
工程结构&模块范例

  1. customdecoration                               // har类型
  2. |---components
  3. |   |---CallbackObserver.ets                   // 自定义装饰器
  4. |   |---MainPage.ets                           // UI页面
复制代码



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

祗疼妳一个

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表