HarmonyOS NEXT 声明式UI语法学习笔记-创建自定义组件

news2025/3/17 6:40:53

基础语法概述

ArkTS的基本组成

装饰器:用于装饰类、结构、方法以及变量,并赋予其特殊含义。如上图都是装饰器,@Component表示自定义组件,@Entry表示表示自定义组件的入口组件,@State表示组件中的状态变量,当状态变量发生变化就会触发UI刷新。

自定义组件:可以复用的UI单元,可组合其他组件,如上述被@Component装饰的struct Index

系统组件:ArkUI框架中默认内置的基础和容器组件,可直接被调用,比如Button、Text、Row等

事件方法:组件可以通过链式调用设置多个事件的响应逻辑,例如Button后面加Onclick() 

声明式UI描述

Text

Text('小说简说简介小说简介小说简介小说简介小说简介小说简介小说简介小说简介小说简介小说简介小说简介小说简介')
        .width('100%')
        .lineHeight(25)
        //文本溢出省略号
        .textOverflow({
          overflow:TextOverflow.Ellipsis
        })
        //文本溢出必须配合maxLines才有效果
        .maxLines(3)

Image

// 加载网络图片
      Image('https://cn-assets.gitee.com/assets/Codeblitz-8824e38875a106e16e29ff57ec977b08.png')
        .height(50)
      // 加载本地图片
      Image($r('app.media.app_icon'))
        .height(50)

配置事件

Button('Click me')
  .onClick(() => {
    this.myText = 'ArkUI';
  })

 使用组件的成员函数配置组件的事件方法,需要bind this。

@State counter:number = 0
Button('add counter'+this.counter)
        .onClick(this.myClickHandler.bind(this))
myClickHandler(): void {
    this.counter += 2;
  }

注意:在 ArkTS 中,不推荐使用成员函数配合 bind(this) 去配置组件的事件方法

1.性能开销:每次渲染都会重新绑定:当使用bind(this)时,每次组件重新渲染,都会创建一个新的函数实例。这是因为bind方法会返回一个新的函数,该函数内部绑定了特定的this值。如果组件频繁重新渲染,会不断创建新的函数实例,增加内存开销,影响性能。

2.代码可读性和维护性:使用 bind(this) 会使代码变得复杂,尤其是在处理多个事件或嵌套组件时,会增加代码的理解难度。开发者需要时刻关注 this 的指向,容易出现混淆

使用声明的箭头函数,可以直接调用,不需要bind this

Button('add counter'+this.counter)
        .onClick(this.fn)
fn = () => {
    this.counter += 1
  }

创建自定义组件

在 ArkUI中,UI显示的内容均为组件,由框架直接提供的组件称为系统组件,由开发者定义的称为自定义组件。在进行UI界面开发时,通常不是把简单的系统组件进行组合使用,可是要考虑代码的复用性、业务逻辑和UI分离,后续版本演进等因素。因此,将UI和部分业务逻辑封装成自定义组件是不可或缺的能力。

自定义组件的基本用法

@Component
struct HelloComponent {
  @State message: string = 'Hello, World!';  

  build() {
    // HelloComponent自定义组件组合系统组件Row和Text
    Row() {
      Text(this.message)
        .onClick(() => {
          // 状态变量message的改变驱动UI刷新,UI从'Hello, World!'刷新为'Hello, ArkUI!'
          this.message = 'Hello, ArkUI!';
        })
    }
  }
}

注意:如果在另外的文件中引用该自定义组件,需要使用export关键字导出,并在使用的页面import该自定义组件。

HelloComponent可以在其他自定义组件中的build()函数中多次创建,实现自定义组件的重用。

@Entry
@Component
struct ParentComponent {  
  build() {
    Column() {
      Text('ArkUI message')
      HelloComponent({ message: 'Hello World!' });  
      Divider()
      HelloComponent({ message: '你好,世界!' });
    }
  }
}

自定义组件的基本结构

struct

自定义组件基于struct实现,struct + 自定义组件名 + {...}的组合构成自定义组件,不能有继承关系。对于struct的实例化,可以省略new。但是要注意,自定义组件名、类名、函数名不能和系统组件名相同。

@Component

@Component装饰器只能装饰在struct关键字声明的数据结构。struct被@Component装饰后才能具备组件化能力,需要实现build方法描述。UI一个struct只能被一个@Component装饰。

在 ArkTS 里,@Component 是用于声明一个组件的装饰器,它可以接受一个可选的布尔类型参数,这个参数是 isStateless,其主要用途在于明确该组件是有状态组件还是无状态组件

参数含义 isStateless 为布尔类型,具体含义如下:

  • true:当传入 true 时,表明该组件是无状态组件。无状态组件不包含自身的状态(如 @State、@Link 等装饰的变量),其 UI 完全由传入的属性决定,只要输入的属性不变,组件的 UI 就不会发生变化。无状态组件相对简单,渲染性能通常更高。
  • false:当传入 false 或者不传入该参数时,默认该组件是有状态组件。有状态组件可以包含自身的状态,这些状态会随着用户操作或其他事件发生改变,从而触发组件的重新渲染以更新 UI。

 代码示例

无状态代码示例:

// 定义一个无状态组件,将 isStateless 参数设置为 true
@Component({ isStateless: true })
struct StatelessComponent {
  // 定义一个属性,用于接收外部传入的值
  msg: string;

  build() {
    // 在组件的构建函数中,使用传入的属性来构建 UI
    Text(this.msg)
      .fontSize(20)
  }
}

// 在另一个组件中使用无状态组件
@Entry
@Component
struct ParentComponent {
  build() {
    Column() {
      // 创建 StatelessComponent 实例,并传入属性值
      StatelessComponent({ msg: 'This is a stateless component.' })
    }
    .width('100%')
  }
}

在上述代码中,StatelessComponent 是一个无状态组件,它没有自己的状态,UI 完全由外部传入的 msg 属性决定。

有状态代码示例:

// 定义一个有状态组件,不传入 isStateless 参数,默认是有状态的
@Component
struct StatefulComponent {
  // 使用 @State 装饰器定义一个有状态的变量
  @State count: number = 0;

  build() {
    Column({ space: 20 }) {
      // 显示当前的计数
      Text(`Count: ${this.count}`)
        .fontSize(20)
      // 创建一个按钮,点击时增加计数
      Button('Increment')
        .onClick(() => {
          this.count++;
        })
    }
    .width('100%')
  }
}

@Entry
@Component
struct MainComponent {
  build() {
    Column() {
      // 使用有状态组件
      StatefulComponent()
    }
    .width('100%')
  }
}

在这个例子中,StatefulComponent 是一个有状态组件,它包含一个 @State 装饰的 count 变量,当用户点击按钮时,count 的值会改变,从而触发组件的重新渲染。

通过传入 isStateless 参数,开发者可以根据组件的特性和需求,灵活选择使用有状态组件或无状态组件,以达到更好的性能和可维护性。

build()函数

 build()函数用于定义自定义组件的声明式UI描述,自定义组件必须定义build()函数

@Component
struct MyComponent {
  build() {
  }
}

@Entry

@Entry装饰的自定义组件将作为UI页面的入口。在单个UI页面中,最多可以使用@Entry装饰一个自定义组件。@Entry可以接受一个可选的
LocalStorage的参数。

LocalStorage 是一种在浏览器(类似概念在 HarmonyOS 等系统中也有应用)中用于存储数据的机制,它允许开发者在客户端本地存储键值对数据,并且这些数据在浏览器会话期间(甚至在浏览器关闭后再次打开时)都会保留,除非手动清除。在 ArkTS 的上下文中,LocalStorage 提供了一种持久化存储应用程序状态或数据的方式,以便在页面重新加载或应用重启后仍能恢复之前的状态。

@Entry
@Component
struct MyComponent {
}

 @Reusable

@Resuable装饰器的主要作用是让组件可以被复用,避免重复创建相同的组件实例,从而提升性能。

应用场景

1. 列表渲染场景

在开发列表类界面时,通常会有大量相同类型的列表项。使用 @Reusable 装饰器可以复用这些列表项组件,减少内存开销和渲染时间。

// 定义可复用的列表项组件
@Reusable('ListItem')
@Component
struct ListItem {
  @Link private item: string;

  build() {
    Row({ space: 5 }) {
      Text(this.item)
        .fontSize(18)
        .margin({ left: 10 })
    }
    .width('100%')
    .padding(10)
    .border({ width: 1, color: Color.Grey })
  }
}

// 使用可复用组件的列表页面
@Component
struct ListPage {
  private listData: string[] = ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5'];

  build() {
    Column({ space: 10 }) {
      ForEach(this.listData, (item: string) => {
        // 复用 ListItem 组件
        ListItem({ item: $item })
      }, (item: string) => item)
    }
    .width('100%')
  }
}

2. 弹窗组件复用

在应用中,可能会多次使用相同样式和功能的弹窗组件,如确认弹窗、提示弹窗等。使用 @Reusable 装饰器可以提高弹窗组件的复用性。

// 定义可复用的确认弹窗组件
@Reusable('ConfirmDialog')
@Component
struct ConfirmDialog {
  @Link private visible: boolean;
  private message: string;
  private onConfirm: () => void;

  build() {
    if (this.visible) {
      Dialog({
        onCancel: () => {
          this.visible = false;
        }
      }) {
        Column({ space: 20 }) {
          Text(this.message)
            .fontSize(18)
          Button('确认')
            .onClick(() => {
              this.visible = false;
              this.onConfirm();
            })
        }
        .width('100%')
        .padding(20)
      }
    }
  }
}

// 使用确认弹窗组件的页面
@Component
struct MainPage {
  @State private showConfirmDialog: boolean = false;

  private confirmAction() {
    console.log('确认操作执行');
  }

  build() {
    Column({ space: 20 }) {
      Button('显示确认弹窗')
        .onClick(() => {
          this.showConfirmDialog = true;
        })
      // 复用确认弹窗组件
      ConfirmDialog({
        visible: $showConfirmDialog,
        message: '确认要执行此操作吗?',
        onConfirm: this.confirmAction
      })
    }
    .width('100%')
    .padding(20)
  }
}

成员函数/变量

自定义组件除了必须要实现build()函数外,还可以实现其他成员函数,成员函数具有以下约束:

  • 自定义组件的成员函数为私有的,且不建议声明成静态函数。

自定义组件可以包含成员变量,成员变量具有以下约束:

  • 自定义组件的成员变量为私有的,且不建议声明成静态变量。

  • 自定义组件的成员变量本地初始化有些是可选的,有些是必选的。具体是否需要本地初始化,是否需要从父组件通过参数传递初始化子组件的成员变量

自定义组件通用样式

自定义组件通过“.”链式调用的形式设置通用样式。

@Component
struct ChildComponent {
  build() {
    Button(`Hello World`)
  }
}

@Entry
@Component
struct MyComponent {
  build() {
    Row() {
      ChildComponent()
        .width(200)
        .height(300)
        .backgroundColor(Color.Red)
    }
  }
}

HarmonyOS官网学习指南

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

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

相关文章

97.HarmonyOS NEXT跑马灯组件教程:基础概念与架构设计

温馨提示:本篇博客的详细代码已发布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下载运行哦! HarmonyOS NEXT跑马灯组件教程:基础概念与架构设计 1. 跑马灯组件概述 跑马灯(Marquee)是一种常见的UI组件&a…

81.HarmonyOS NEXT 状态管理与响应式编程:@Observed深度解析

温馨提示:本篇博客的详细代码已发布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下载运行哦! HarmonyOS NEXT 状态管理与响应式编程:Observed深度解析 文章目录 HarmonyOS NEXT 状态管理与响应式编程:Observed深度解析…

股指期货有卖不出去的时候吗?

在股指期货的交易世界里,很多人都有这样的疑问:股指期货会不会有卖不出去的时候呢?答案是会的,下面咱们就来详细唠唠为啥会出现这种情况。 市场极端行情下难以卖出 1.跌停限制:股指期货和股票一样,也有涨…

开发、科研、日常办公工具汇总(自用,持续更新)

主要记录汇总一下自己平常会用到的网站工具,方便查阅。 update:2025/2/11(开发网站补一下) update:2025/2/21(补充一些AI工具,刚好在做AI视频相关工作) update:2025/3/7&…

HTML5 drag API实现列表拖拽排序

拖拽API(Drag and Drop API)是HTML5提供的一组功能,使得在网页上实现拖放操作变得更加简单和强大。这个API允许开发者为网页元素添加拖拽功能,用户可以通过鼠标将元素拖动并放置到指定的目标区域。 事件类型 dragstart&#xff1…

改变一生的思维模型【11】升维

升维思维模型:突破认知局限的破局法则 一、定义与核心逻辑 升维思维是通过增加分析维度,将问题投射到更高认知层次寻找解决方案的思考方式。其本质是跳出原有竞争维度,在更广阔的空间重构游戏规则。核心逻辑在于:当低维战场陷入…

【动手学深度学习】#2线性神经网络

主要参考学习资料: 《动手学深度学习》阿斯顿张 等 著 【动手学深度学习 PyTorch版】哔哩哔哩跟李牧学AI 目录 2.1 线性回归2.1.1 线性回归的基本元素线性模型损失函数解析解随机梯度下降 2.1.3 最大似然估计 2.2 线性回归从零开始实现2.2.1 生成数据集2.2.2 读取数…

计算机网络——NAT

一、什么是NAT? NAT(Network Address Translation,网络地址转换) 是一种将 私有IP地址 与 公有IP地址 相互映射的技术,主要用于解决IPv4地址不足的问题。它像一名“翻译官”,在数据包经过路由器或防火墙时…

同一子网通信

添加交换机后的通信流程 1. 同一子网内(使用交换机) 判断是否在同一子网: 主机A通过子网掩码判断主机B的IP地址是否属于同一子网。若在同一子网,主机A需要通过ARP获取主机B的MAC地址。 ARP请求(广播)&…

IntelliJ IDEA 快捷键系列:重命名快捷键详解

目录 引言一、默认重命名快捷键1. Windows 系统‌2. Mac 系统‌ 二、操作步骤与技巧1. 精准选择重命名范围‌2. 智能过滤无关内容‌ 三、总结 引言 在代码重构中,‌重命名变量、类、方法‌ 是最常用的操作之一。正确使用快捷键可以极大提升开发效率。本文针对 ‌Ma…

零基础掌握分布式ID生成:从理论到实战的完整指南 [特殊字符]

一、为什么需要分布式ID? 🤔 在单机系统中,使用数据库自增ID就能满足需求。但在分布式系统中,多个服务节点同时生成ID时会出现以下问题: ID冲突:不同节点生成相同ID 扩展困难:数据库自增ID无法…

使用python反射,实现pytest读取yaml并发送请求

pytest yaml yaml - feature: 用户模块story: 登录title: 添加用户request:method: POSTurl: /system/user/listheaders: nullparams: nullvalidate: nullread_yaml_all def read_yaml_all(path):with open(path, r, encodingutf-8) as f:value yaml.safe_load(f)return v…

Matlab 汽车悬架系统动力学建模与仿真

1、内容简介 略 Matlab 170-汽车悬架系统动力学建模与仿真 可以交流、咨询、答疑 2、内容说明 略 本文对题目给定的1/2汽车四自由度模型,建立状态空间模型进行系统分析,并通过MATLAB仿真对系统进行稳定性、可控可观测性分析,对得的结果进行…

专访数势科技谭李:智能分析 Agent 打通数据平权的最后一公里

作者|斗斗 编辑|皮爷 出品|产业家 伦敦塔桥下的泰晤士河底,埋藏着工业革命的隐秘图腾——布鲁内尔设计的隧道盾构机。在19世纪城市地下轨道建设的过程中,这个直径11米的钢铁巨兽没有选择拓宽河道,而是开创了地下通行的新维度。 “我们不…

2、操作系统之软件基础

一、硬件支持系统 ,系统管理硬件 操作系统核心功能可以分为: 守护者:对硬件和软件资源的管理协调者:通过机制,将各种各样的硬件资源适配给软件使用。 所以为了更好的管理硬件,操作系统引进了软件。其中3大…

STC89C52单片机学习——第20节: [8-2]串口向电脑发送数据电脑通过串口控制LED

写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做! 本文写于:2025.03.15 51单片机学习——第20节: [8-2]串口向电脑发送数据&电脑通过串口控制LED 前言…

K8S下nodelocaldns crash问题导致域名请求响应缓慢

前言 最近做项目,有业务出现偶发的部署导致响应很慢的情况,据了解,业务使用域名访问,相同的nginx代理,唯一的区别就是K8S重新部署了。那么问题大概率出现在容器平台,毕竟业务是重启几次正常,偶…

CVPR2024 | TT3D | 物理世界中可迁移目标性 3D 对抗攻击

Towards Transferable Targeted 3D Adversarial Attack in the Physical World 速览总结摘要-Abstract引言-Introduction相关工作-Related Work方法-MethodologyPreliminray-预备知识问题表述-Problem FormulationNeRF参数空间中的双重优化-Dual Optimization in NeRF Paramete…

全面对比分析:HDMI、DP、DVI、VGA、Type-C、SDI视频接口特点详解

在当今的多媒体时代,视频接口的选择对于设备连接和显示效果至关重要。不同的视频接口在传输质量、兼容性、带宽等方面各有优劣。本文将全面对比分析常用的视频接口HDMI、DP、DVI、VGA、Type-C、SDI,帮助读者更好地理解它们的特点和适用场景。 一、HDMI&…

传输层自学

传输实体:完成传输层任务的硬件或软件 可能位于: 操作系统内核独立的用户进程绑定在网络应用中的链接库网络接口卡 1.功能: 网络层与传输层作用范围比较? 网络层负责把数据从源机送达到目的机 传输层负责把数据送达到具体的应…