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

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

基础语法概述

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官网学习指南

原文地址:https://blog.csdn.net/m0_64671979/article/details/146212664
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.kler.cn/a/589245.html

相关文章:

  • 麒麟服务器操作系统QT系列软件工具手册
  • AD9850函数信号发生器制作(全套资料)
  • RK3568 android11 基于PN7160的NXP NFC移植
  • ASP.NET Webform和ASP.NET MVC 后台开发 大概80%常用技术
  • 操作系统的磁盘调度
  • 鸿蒙Next开发中的坑与问题总结
  • 五大基础算法——枚举算法
  • 从被动响应到主动预见:智能可观测性技术的变革与实践
  • Qt常见面试题合集
  • ⚡️Jolt -- 通过JSON配置来处理复杂数据转换的工具
  • Spring cloud Gateway中的GlobalFilter接口及其方法
  • Spring Boot 核心知识点精讲:助你快速上手与深度理解
  • Linux下部署前后端分离项目 —— Linux下安装nginx
  • oracle实例
  • ai智能语音机器人对我们生活有什么影响
  • Designing Dashboards with SAP Analytics Cloud
  • RNN 实战指南:用 PyTorch 从零实现文本分类
  • 【从零开始学习计算机科学】编译原理(一)编译过程概述
  • tcp/ip三次握手和四次挥手原理详细解析
  • Java学习——day21