鸿蒙Next-方法装饰器以及防抖方法注解实现

news2025/2/26 20:45:19

以下是关于 鸿蒙Next(HarmonyOS NEXT)中 MethodDecorator 的详细介绍及使用指南,结合了多个技术来源的实践总结:


一、MethodDecorator 的概念与作用

MethodDecorator 是鸿蒙Next框架中用于装饰类方法的装饰器,属于 ArkUI 装饰器体系 的一部分。它允许开发者为类方法动态添加元数据或功能扩展,例如实现方法拦截、状态监听、日志记录等场景。通过装饰器,开发者能以声明式的方式增强代码的可维护性和复用性。

核心特点:
  1. 非侵入式增强:在不修改原方法逻辑的前提下,通过装饰器注入额外逻辑。

  2. 元数据绑定:可为方法添加配置信息(如参数校验规则、权限控制标记)。

  3. 与状态管理联动:常与 @State@Prop 等状态装饰器结合,实现数据变化响应。


二、MethodDecorator 的语法与使用示例

1. 基本语法
function MyMethodDecorator(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  // 装饰器逻辑:修改或增强原方法
  const originalMethod = descriptor.value;
  descriptor.value = function (...args: any[]) {
    console.log(`方法 ${propertyKey} 被调用`);
    return originalMethod.apply(this, args);
  };
  return descriptor;
}

class MyClass {
  @MyMethodDecorator
  myMethod() {
    // 原方法逻辑
  }
}
2. 常见使用场景

(1) 方法调用日志记录

function LogMethod() {
  return function (target: any, methodName: string, descriptor: PropertyDescriptor) {
    const original = descriptor.value;
    descriptor.value = function (...args: any[]) {
      console.log(`调用方法:${methodName},参数:${JSON.stringify(args)}`);
      return original.apply(this, args);
    };
  };
}

@Component
struct MyComponent {
  @LogMethod()
  handleClick() {
    // 处理点击事件
  }
}

(2) 状态监听与联动通过 @Watch 装饰器(内置的 MethodDecorator)监听状态变量变化并触发方法:

@Component
struct MyComponent {
  @State count: number = 0;

  @Watch('count') // 监听 count 变化
  onCountChanged(newValue: number, oldValue: number) {
    console.log(`count 从 ${oldValue} 变为 ${newValue}`);
  }

  build() {
    Button('增加').onClick(() => this.count++);
  }
}

此例中,@Watch 装饰器会在 count 变化时自动调用 onCountChanged 方法。

(3) 点击事件防抖

//period间隔时间
@Debounce(2000)
clickMethod(){
}
function Debounce(period: number = 750): MethodDecorator {
  return function (
      target: object,
      propertyKey: string,
      descriptor: PropertyDescriptor
  ): PropertyDescriptor {
    const originalMethod = descriptor.value
    let timeId: number = 0
    descriptor.value = function (...args: object[]): void {
      if (timeId !== 0) {
        clearTimeout(timeId)
      }
      timeId = setTimeout(() => {
        originalMethod.apply(this, args)
        timeId = 0
      },
        period
      )
    }
    return descriptor
  }
}

(4) 监听某个方法的耗时

function MonitorCostTime(): MethodDecorator {
  return function (target: object,
    propertyKey: string,
    descriptor: PropertyDescriptor) {
    const originMethod = descriptor.value

    descriptor.value = function (...args: object[]) {
      let startTime = systemDateTime.getTime()
      const result = originMethod.apply(this, args); // 调用原始方法
      const endTime = systemDateTime.getTime(); // 获取方法执行后的时间
      hilog.error(hilog.LogLevel.ERROR, "monitorCostTime", `方法消耗的时间为:${endTime - startTime}s`)
      return result;
    }
    return descriptor
  }
}

(5) 权限控制

function CheckPermission(permission: string) {
  return function (target: any, methodName: string, descriptor: PropertyDescriptor) {
    const original = descriptor.value;
    descriptor.value = function (...args: any[]) {
      if (hasPermission(permission)) {
        return original.apply(this, args);
      } else {
        console.error('无权限执行此操作');
      }
    };
  };
}

class UserService {
  @CheckPermission('admin')
  deleteUser() {
    // 删除用户逻辑
  }
}

三、与 ArkUI 框架的深度集成

1. 生命周期方法装饰

鸿蒙Next的组件生命周期方法(如 aboutToAppearaboutToDisappear)本质上是内置的 MethodDecorator,开发者可通过自定义装饰器扩展生命周期行为:

function TrackLifecycle() {
  return function (target: any, methodName: string, descriptor: PropertyDescriptor) {
    const original = descriptor.value;
    descriptor.value = function (...args: any[]) {
      console.log(`组件生命周期方法 ${methodName} 被触发`);
      return original.apply(this, args);
    };
  };
}

@Component
struct MyComponent {
  @TrackLifecycle()
  aboutToAppear() {
    // 组件初始化逻辑
  }
}
2. 动画与交互增强

结合 animateTo 方法,可通过装饰器封装动画逻辑:

function FadeAnimation(duration: number) {
  return function (target: any, methodName: string, descriptor: PropertyDescriptor) {
    const original = descriptor.value;
    descriptor.value = function (...args: any[]) {
      animateTo({
        duration: duration,
        onFinish: () => original.apply(this, args)
      }, () => {
        this.opacity = 0;
      });
    };
  };
}

@Component
struct AnimatedButton {
  @State opacity: number = 1;

  @FadeAnimation(300)
  handleClick() {
    // 点击后的业务逻辑
  }

  build() {
    Button('点击').opacity(this.opacity).onClick(() => this.handleClick());
  }
}

四、注意事项与最佳实践

  1. 装饰器执行顺序
    多个装饰器按 从下到上 的顺序执行(装饰器工厂函数从外到内)。

  2. 避免副作用
    装饰器应保持无状态,避免修改全局变量或依赖外部环境。

  3. 性能优化
    高频调用的方法慎用复杂装饰器逻辑,必要时通过缓存优化。

  4. 兼容性
    确保装饰器与鸿蒙Next的 API 版本兼容,避免使用实验性特性。


五、扩展应用:自定义高级装饰器

1. 异步方法拦截
function Retry(maxAttempts: number) {
  return function (target: any, methodName: string, descriptor: PropertyDescriptor) {
    const original = descriptor.value;
    descriptor.value = async function (...args: any[]) {
      let attempts = 0;
      while (attempts < maxAttempts) {
        try {
          return await original.apply(this, args);
        } catch (error) {
          attempts++;
          console.log(`重试第 ${attempts} 次`);
        }
      }
      throw new Error('操作失败');
    };
  };
}

class ApiService {
  @Retry(3)
  async fetchData() {
    // 网络请求逻辑
  }
}
2. 参数校验
function ValidateParams(...validators: Function[]) {
  return function (target: any, methodName: string, descriptor: PropertyDescriptor) {
    const original = descriptor.value;
    descriptor.value = function (...args: any[]) {
      validators.forEach((validator, index) => {
        if (!validator(args[index])) {
          throw new Error(`参数 ${index} 校验失败`);
        }
      });
      return original.apply(this, args);
    };
  };
}

class Calculator {
  @ValidateParams(
    (x: number) => !isNaN(x),
    (y: number) => y !== 0
  )
  divide(x: number, y: number) {
    return x / y;
  }
}

总结

MethodDecorator 是鸿蒙Next开发中实现 代码复用 和 逻辑解耦 的重要工具。通过合理使用内置装饰器(如 @Watch)和自定义装饰器,开发者可以显著提升代码的可维护性,同时实现复杂的业务逻辑与交互效果。实际开发中需结合具体场景选择装饰器策略,并注意性能与兼容性问题。

关注我获取更多知识或者投稿

d625635cc096aea7ecdeace5281677e2.jpeg

335e9bf34e8e735ab06ed9e857cd1c51.jpeg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2306555.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机网络:应用层 —— 电子邮件

文章目录 电子邮件的起源与发展电子邮件的组成电子邮件协议邮件发送和接收过程邮件发送协议SMTP协议多用途因特网邮件扩展MIME 电子邮件的信息格式 邮件读取协议邮局协议POP因特网邮件访问协议IMAP 基于万维网的电子邮件 电子邮件&#xff08;E-mail&#xff09;是因特网上最早…

zyNo.26

[GXYCTF2019]Ping Ping Ping&#xff08;Web&#xff09; 传/&#xff1f;ip1有ping回显&#xff0c;说明后端可能通过php参数接受了ip参数&#xff0c;并且拼接到了最终执行的命令里形成了ping -c 3$ip&#xff0c;这样可能存在一个命令注入漏洞 要判断是否符合 ping -c 3$ip …

ui设计公司兰亭妙微分享:科研单位UI界面设计

科研单位的UI界面设计是一项至关重要的任务&#xff0c;它不仅关乎科研工作的效率&#xff0c;还直接影响到科研人员的用户体验。以下是对科研单位UI界面设计的详细分析&#xff1a; 一、设计目标 科研单位的UI界面设计旨在提升科研工作的效率与便捷性&#xff0c;同时确保科…

OpenGL ES -> GLSurfaceView绘制点、线、三角形、正方形、圆(顶点法绘制)

XML文件 <?xml version"1.0" encoding"utf-8"?> <com.example.myapplication.MyGLSurfaceViewxmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"…

AndroidAOSP定制隐藏某个应用的图标

AndroidAOSP定制隐藏某个应用的图标 1.前言: 之前在做AOSP定制的时候需要隐藏某些App的图标&#xff0c;或者默认不显示某个定制的App图标&#xff0c;这样可以让用户感觉不到已经安装了某个App,或者在做系统定制的时候需要修改桌面icon,有些系统的App图标默认不需要显示&…

最小化重投影误差求解PnP

问题描述 已知n个空间点 P i [ x i , y i , z i ] T P_i[x_i,y_i,z_i]^T Pi​[xi​,yi​,zi​]T&#xff0c;其投影的像素坐标 p i [ u i , v i ] T p_i[u_i,v_i]^T pi​[ui​,vi​]T求相机的位姿R&#xff0c;T。 问题分析 根据相机模型&#xff0c;像素点和空间点的位置…

unity学习52:UI的最基础组件 rect transform,锚点anchor,支点/轴心点 pivot

目录 1 image 图像&#xff1a;最简单的UI 1.1 图像的基本属性 1.2 rect transform 1.3 image的component: 精灵 → 图片 1.4 修改颜色color 1.5 修改材质 1.6 raycast target 1.7 maskable 可遮罩 1.8 imageType 1.9 native size 原生大小 2 rect transform 2.1 …

【Python系列】PYTHONUNBUFFERED=1的作用

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

Linux中的cgdb的基本使用

1.cgdb的简介 Linux中的cgdb是一个基于GDB&#xff08;GNU Debugger&#xff09;的图形化调试前端&#xff0c;它结合了GDB的命令行界面功能和代码查看窗口&#xff0c;为开发者提供了一个更为直观的调试体验。 cgdb的作用和功能&#xff1a; 直观调试体验&#xff1a;cgdb提供…

解决idea2019创建springboot项目爆红的问题

通过spring Initializr创建springboot项目时&#xff0c;由于idea版本太低&#xff0c;创建完成后需要手动修改pom.xml&#xff0c;对小白不太友好 一个简便的方法&#xff0c;配置好pom.xml文件的各个版本&#xff1a; 在 https://start.aliyun.com/ 上选择好后复制pom.xml代…

DeepSeek 提示词:基础结构

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…

自动驾驶两个传感器之间的坐标系转换

有两种方式可以实现两个坐标系的转换。 车身坐标系下一个点p_car&#xff0c;需要转换到相机坐标系下&#xff0c;旋转矩阵R_car2Cam&#xff0c;平移矩阵T_car2Cam。点p_car在相机坐标系下记p_cam. 方法1&#xff1a;先旋转再平移 p_cam T_car2Cam * p_car T_car2Cam 需要注…

[实现Rpc] 客户端 | Requestor | RpcCaller的设计实现

目录 Requestor类的实现 框架 完善 onResponse处理回复 完整代码 RpcCaller类的实现 1. 同步调用 call 2. 异步调用 call 3. 回调调用 call Requestor类的实现 &#xff08;1&#xff09;主要功能&#xff1a; 客户端发送请求的功能&#xff0c;进行请求描述对服务器…

smolagents学习笔记系列(五)Tools-in-depth-guide

这篇文章锁定官网教程中的 Tools-in-depth-guide 章节&#xff0c;主要介绍了如何详细构造自己的Tools&#xff0c;在之前的博文 smolagents学习笔记系列&#xff08;二&#xff09;Agents - Guided tour 中我初步介绍了下如何将一个函数或一个类声明成 smolagents 的工具&…

axios几种请求类型的格式

Axios 是一个基于 Promise 的 HTTP 客户端&#xff0c;广泛用于浏览器和 Node.js 中发送 HTTP 请求。它支持多种请求格式&#xff0c;包括 GET、POST、PUT、DELETE 等。也叫RESTful 目录 一、axios几种请求类型的格式 1、get请求 2、post请求 3、put请求 4、delete请求 二…

架构设计系列(六):缓存

一、概述 在应用对外提供服务的时候其稳定性&#xff0c;性能会受到诸多因素的影响。缓存的作用是将频繁访问的数据缓存起来&#xff0c;避免资源重复消耗&#xff0c;提升系统服务的吞吐量。 二、缓存的应用场景 2.1 客户端 HTTP响应可以被浏览器缓存。我们第一次通过HTTP请…

个人电脑小参数GPT预训练、SFT、RLHF、蒸馏、CoT、Lora过程实践——MiniMind图文版教程

最近看到Github上开源了一个小模型的repo&#xff0c;是真正拉低LLM的学习门槛&#xff0c;让每个人都能从理解每一行代码&#xff0c; 从零开始亲手训练一个极小的语言模型。开源地址&#xff1a; GitHub - jingyaogong/minimind: &#x1f680;&#x1f680; 「大模型」2小时…

格式工厂 FormatFactory v5.18.便携版 ——多功能媒体文件转换工具

格式工厂 FormatFactory v5.18.便携版 ——多功能媒体文件转换工具 功能&#xff1a;视频 音频 图片 文档PDF格式 各种转换&#xff0c;同格式调整压缩比例&#xff0c;调整大小 特色&#xff1a;果风图标 好看; 支持多任务队列&#xff0c;完成自动关机 下载地址&#xff1…

KafkaTool

Offset Explorer 第一次打开需要配置kafka相关配置连接 随便先启动一个Kafka(先启动zookeeper) 设置key value 记得刷新

基于C++“简单且有效”的“数据库连接池”

前言 数据库连接池在开发中应该是很常用的一个组件&#xff0c;他可以很好的节省连接数据库的时间开销&#xff1b;本文基使用C实现了一个简单的数据库连接池&#xff0c;代码量只有400行只有&#xff0c;但是压力测试效果很好&#xff1b;欢迎收藏 关注&#xff0c;本人将会…