鸿蒙开发:了解@Builder装饰器

前言

本文代码案例基于Api13,温馨提示:内容相对来说比较简单,如果您已掌握,略过即可。

如果说一个页面中组件有很多,我们都统一写到build函数中,显而易见,会导致build函数代码非常冗余,并且在有相同UI时,也做不到可复用效果,那么,针对这一问题如何解决呢?答案就是抽取出来;在页面内实现UI组件的抽取剥离,其实,在实际的开发中是非常常见的,也就是通过@Builder装饰器来实现。

简单案例

以下是一个多文本展示案例,非常简单,就是几个Text组件,未抽取之前,都统一写在build函数之中。

@Entry
@Component
struct Index {build() {Column() {Text("文本测试一").fontSize(20).fontWeight(FontWeight.Bold)Text("文本测试二").fontSize(20).fontWeight(FontWeight.Bold)Text("文本测试三").fontSize(20).fontWeight(FontWeight.Bold)Text("文本测试四").fontSize(20).fontWeight(FontWeight.Bold)}.height('100%').width('100%')}
}

使用@Builder装饰器之后:

@Entry
@Component
struct Index {@BuildertextView(text: string) {Text(text).fontSize(20).fontWeight(FontWeight.Bold)}build() {Column() {this.textView("文本测试一")this.textView("文本测试二")this.textView("文本测试三")this.textView("文本测试四")}.height('100%').width('100%')}
}

显而可见,代码相比未抽取之前,简洁了很多,虽然上述只是一个案例,然而在实际的开发中,页面的复杂程度远远比案例复杂,所以更应该合理的使用@Builder装饰器

什么是@Builder?

在前言中已经明确告知,@Builder它是一个装饰器,主要用于UI元素的复用以及抽取,@Builder所修饰的函数,统称为“自定义构建函数”,可以在函数中定义任何的UI组件,用法和build中的使用是一样的。

使用方式

@Builder装饰器有两种使用方式,一种是定义在UI组件内,也就是上述的使用方式,可以称为私有自定义构建函数,也就是只能给当前的UI组件进行使用,别的UI组件是无法使用的。

与私有自定义构建函数相对应的就是全局自定义构建函数,它可以实现任意的UI组件进行使用,需要用到function关键字,如果定义在非UI组件中,需要用export关键字导出。

我们可以自定义一个扩展类,把共用的组件定义在这里。

@Builder
export function TextView(text: string) {Text(text).fontSize(20).fontWeight(FontWeight.Bold)
}

任何一个页面或者UI组件中都可以使用。

import { TextView } from './BuilderView'@Entry
@Component
struct Index {build() {Column() {TextView("文本测试一")TextView("文本测试二")TextView("文本测试三")TextView("文本测试四")}.height('100%').width('100%')}
}

当然了,如果不是全局共用,仅仅是本页面内共用,也可以使用这种方式来实现。

数据更新

当我们直接更改传递的变量时,会发现@Builder修饰的函数内并没有实现数据改变,如下案例,怎么点击Button都不会发生改变。

@Entry
@Component
struct Index {@State testContent: string = "文本测试"@BuildertextView(text: string) {Text(text).fontSize(20).fontWeight(FontWeight.Bold)}build() {Column() {this.textView(this.testContent)Button("改变").margin({ top: 10 }).onClick(() => {this.testContent = "文本测试2"})}.height('100%').width('100%').justifyContent(FlexAlign.Center)}
}

这是因为,在@Builder修饰的函数内部,不允许改变参数值,也就是状态变量的改变不会引起@Builder方法内的UI刷新,那么要怎么实现可以动态改变@Builder修饰的函数里的数据呢,有两种方式,一种是,直接把当前的引用也就是当前的类传递过去,直接调用,另一种则是使用引用传递。

this指向当前类

把以上的代码做下更改,由传递值,直接传递当前的类,也就是当前的this,由this直接调用。

@Entry
@Component
struct Index {@State testContent: string = "文本测试"@BuildertextView(_this: Index) {Text(_this.testContent).fontSize(20).fontWeight(FontWeight.Bold)}build() {Column() {this.textView(this)Button("改变").margin({ top: 10 }).onClick(() => {this.testContent = "文本测试2"})}.height('100%').width('100%').justifyContent(FlexAlign.Center)}
}

可以发现点击Button后,数据实现了动态改变。

按引用传递参数

直接传递当前的this,可以说是最简单的方式,除了这种方式之外,我们还可是使用引用传递参数的方式,动态改变数据,也就是通过传递对象的方式。

class TestBean {testContent?: string;
}@Entry
@Component
struct Index {@State testContent: string = "文本测试"@BuildertextView(testBean: TestBean) {Text(testBean.testContent).fontSize(20).fontWeight(FontWeight.Bold)}build() {Column() {this.textView({ testContent: this.testContent })Button("改变").margin({ top: 10 }).onClick(() => {this.testContent = "文本测试2"})}.height('100%').width('100%').justifyContent(FlexAlign.Center)}
}

可以看到,以上的数据传递,也能实现数据的动态改变,相对于this传递,使用这种方式则更加灵活,毕竟在实际的开发中,我们可能会遇到多个页面共用组件的情况,传递this显然只适合当前的页面,如果多个页面复用,还是以对象形式传递为佳。

由此可见,在使用@Builder进行参数传递的时候,如果要引起@Builder方法内的UI刷新,可以按照引用传递参数进行实现,按值传递是无法更新UI的。

参数规则

@Builder修饰的函数,其定义的参数类型,必须和传递的类型保持一致,并且不允许undefined、null和返回undefined、null的表达式。

还有一点非常重要,@Builder如果传入的参数是两个或两个以上,不会触发动态渲染UI,比如,上面的案例中,我们随便增加一个参数。

 @BuildertextView(testBean: TestBean, isBoolean: boolean) {Text(testBean.testContent).fontSize(20).fontWeight(FontWeight.Bold)}

运行后可以发现,数据是无法动态更改的,如果有多个值如何传递呢?两种方式,第一种以this为传递对象,使用this调用更多定义的参数,第二种就是直接定义在对象里,既然都以对象的形式进行传递了,何不都直接定义在对象里呢?

@ComponentV2装饰器更新

使用ComponentV2装饰器,遵循的道理一样,也就是使用简单数据类型不可以触发UI的刷新。

@Entry
@ComponentV2
struct Index {@Local testContent: string = "文本测试"@BuildertextView(testContent: string) {Column() {Text(testContent).fontSize(20).fontWeight(FontWeight.Bold)}}build() {Column() {this.textView(this.testContent)Button("改变").margin({ top: 10 }).onClick(() => {this.testContent = "文本测试2"})}.height('100%').width('100%').justifyContent(FlexAlign.Center)}
}

如果要更新UI的话,还是需要按引用传递参数,也就是修改为对象传递。

class TestBean {testContent?: string;
}@Entry
@ComponentV2
struct Index {@Local testContent: string = "文本测试"@BuildertextView(testBean: TestBean) {Column() {Text(testBean.testContent).fontSize(20).fontWeight(FontWeight.Bold)}}build() {Column() {this.textView({ testContent: this.testContent })Button("改变").margin({ top: 10 }).onClick(() => {this.testContent = "文本测试2"})}.height('100%').width('100%').justifyContent(FlexAlign.Center)}
}

如果直接以对象的形式传递,不借助成员变量,需要使用@ObservedV2修饰的对象类和@Trace修饰属性才可以触发UI的刷新。

@ObservedV2
class TestBean {@Trace testContent: string = "文本测试";
}@Entry
@ComponentV2
struct Index {@Local testBean: TestBean = new TestBean()@BuildertextView(testBean: TestBean) {Column() {Text(testBean.testContent).fontSize(20).fontWeight(FontWeight.Bold)}}build() {Column() {this.textView(this.testBean)Button("改变").margin({ top: 10 }).onClick(() => {this.testBean.testContent = "文本测试2"})}.height('100%').width('100%').justifyContent(FlexAlign.Center)}
}

相关总结

@Builder装饰是鸿蒙UI开发中,非常重要的一个装饰器,在实际的开发中,合理且正确的使用,能够让我们的代码更加的简洁,有两点需要注意,一是,是用私有还是全局,取决于当前的组件的复用机制,如果多个页面都使用了,建议以全局为主;二是传参的动态更新,有更新就使用引用参数传递,没有更新按值传递即可。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一文深入了解DeepSeek-R1:模型架构

本文深入探讨了 DeepSeek-R1 模型架构。让我们从输入到输出追踪 DeepSeek-R1 模型,以找到架构中的新发展和关键部分。DeepSeek-R1 基于 DeepSeek-V3-Base 模型架构。本文旨在涵盖其设计的所有重要方面。 📝 1. 输入上下文长度 DeepSeek-R1的输入上下文长…

Linux进程管理

一、进程查看 1、进程 进程 process 计算机执行任务的最小单位 2、进程查看 ps auxa:all u:user x:所有终端 所有用户所有终端的所有进程 COMMAND: 进程名称 USER: 启动进程的用户&…

(5/100)每日小游戏平台系列

新增一个数字迷宫游戏! 数字迷宫游戏是一款基于迷宫探索的益智游戏。玩家从迷宫的起点出发,必须根据迷宫中的数字指示,选择正确的方向,通过迷宫最终到达终点。游戏的目标是尽快找到并到达终点。 游戏规则 起点与终点:…

latex二重闭合积分显示

latex二重闭合积分显示 环境 texlive2024texstdio4.8.6 解决 添加宏包 \usepackage{esint} % 在导言区加载宏包符号 \oiint测试 documentclass[12pt]{article} \usepackage{esint} % 在导言区加载宏包 \title{Hello} \author{Houor}\begin{document}\maketitleHello, \L…

WebP2P+自研回音消除:视频通话SDK嵌入式EasyRTC构建高交互性音视频应用

随着移动互联网时代的到来,手机端的扬声器大多采用外置设计,且音量较大。在这种情况下,扬声器播放的声音更容易被麦克风捕捉,从而导致回声问题显著加剧。这种设计虽然方便用户在免提模式下使用,但也带来了更复杂的音频…

二分查找sql时间盲注,布尔盲注

目录 一:基础知识引导 数据库:information_schema里面记录着数据库的所有元信息 二,布尔盲注,时间盲注 (1)布尔盲注案例(以sqli-labs第八关为例): (2&am…

机器学习 - 理论和定理

在机器学习中,有一些非常有名的理论或定理,对理解机器学习的内在特性非常有帮助。本文列出机器学习中常用的理论和定理,并举出对应的举例子加以深化理解,有些理论比较抽象,我们可以先记录下来,慢慢啃&#…

Linux Mem -- ARM8.5-A Memory Tagging Extension

目录 1 介绍 2 威胁模型 3 MTE的内存安全 4 架构细节 5 在ARMv8-A架构,MTE添加了如下指令,可根据策略分为三种: 6 大量部署MTE 7 MTE的硬件层部署 8 MTE的软件层部署 8.1 Heap Tagging 8.2 Stack Tagging 9 MTE优化 近期在深入了解A…

深入剖析推理模型:从DeepSeek R1看LLM推理能力构建与优化

著名 AI 研究者和博主 Sebastian Raschka 又更新博客了。原文地址:https://sebastianraschka.com/blog/2025/understanding-reasoning-llms.html。这一次,他将立足于 DeepSeek 技术报告,介绍用于构建推理模型的四种主要方法,也就是…

如何保持 mysql 和 redis 中数据的一致性?PegaDB 给出答案

MySQL 与 Redis 数据保持一致性是一个常见且复杂的问题,一般来说需要结合多种策略来平衡性能与一致性。 传统的解决策略是先读缓存,未命中则读数据库并回填缓存,但方式这种维护成本较高。 随着云数据库技术的发展,目前国内云厂商…

Vue 入门到实战 十

第10章 Vue Router​​​​​​​ 目录 10.1 什么是路由 10.2 Vue Router的安装 10.2.1 本地独立版本方法 10.2.2 CDN方法 10.2.3 NPM方法 10.2.4 命令行工具(Vue CLI)方法 10.3 Vue Router的基本用法 10.3.1 跳转与传参 10.3.2 配置路由 10.…

Java并发中的CAS机制:原理、应用与挑战(通俗易懂版)

上一期文章内容:Java并发中的乐观锁与悲观锁, 本期文章我们来讲一下Java并发中的CAS机制 一、从银行账户案例理解CAS CAS 是一种乐观锁机制,用于在不使用锁的情况下实现多线程对共享资源的并发访问。 它包含三个操作数:内存位置&a…

SpringBoot自动配置-以Mybatis配置为例

SpringBoot自动配置 无基础的直接看链接内容,有基础就直接顺着往下看就可以 Spring底层(自动配置) 自动配置就是EnableXXX封装Improt(ImportSelector的实现类)对应方法selectImoprt返回字符串数组为类名会注册为bean…

2025 docker可视化管理面板DPanel的安装

1.什么是 DPanel ? DPanel 是一款 Docker 可视化管理面板,旨在简化 Docker 容器、镜像和文件的管理。它提供了一系列功能,使用户能够更轻松地管理和部署 Docker 环境。 软件特点: 可视化管理:提供直观的用户界面&#…

DeepSeek从入门到精通(清华大学)

​ DeepSeek是一款融合自然语言处理与深度学习技术的全能型AI助手,具备知识问答、数据分析、编程辅助、创意生成等多项核心能力。作为多模态智能系统,它不仅支持文本交互,还可处理文件、图像、代码等多种格式输入,其知识库更新至2…

Word 里面嵌入DeepSeek

目录 一、问题描述 二、解决方法 三、代码 四、注意事项 五、总结 一、问题描述 如何在Word里面嵌入DeepSeek? 二、解决方法 1、新建文档,按 AltF11,进入VB界面。 2、选中文档,右键->插入->模块。 3、进入模块,粘入…

java面试题-集合篇

Collection 1.Collection有哪些类? Java集合框架中的Collection接口是所有集合类的基础接口,定义了一些基本的集合操作,如添加元素、删除元素、判断是否包含某个元素等。常见的集合类包括List、Set和Queue。 List List接口定义了按照索引…

国内 网络安全沙箱

CSRF攻击 CSRF攻击概述: CSRF(Cross Site Request Forgery, 跨站域请求伪造)是一种网络的攻击方式,它在 2007 年曾被列为互联网 20 大安全隐患之一。其他安全隐患,比如 SQL 脚本注入,跨站域脚本攻击等在近…

Web3 的虚实融合之路:从虚拟交互到元宇宙构建

在这个数字技术日新月异的时代,我们正站在 Web3 的门槛上,见证着互联网的又一次革命。Web3 不仅仅是技术的迭代,它代表了一种全新的交互方式和价值创造模式。本文将探讨 Web3 如何推动虚拟交互的发展,并最终实现元宇宙的构建&…

项目中菜单按照层级展示sql

效果如图: 直接上脚本 查四级菜单 select EFT_FLAG,MENU_ID, CASE LEN(MENU_LVL)WHEN 4THEN MENU_NAME ELSE - END AS MENU_NAME1, CASE LEN(MENU_LVL)WHEN 8THEN MENU_NAME ELSE - END AS MENU_NAME2, CASE LEN(MENU_LVL)WHEN 12THEN MENU_NAME ELSE - END …