2.2 从零写一个登录页:声明式 UI 初体验


2.2 从零写一个登录页:声明式 UI 初体验

本节摘要:不靠模板,从空白文件手写一个含标题、两个输入框、按钮与点击响应的登录页,过程中拆解 ArkTS 页面的三层语法:装饰器组件层、build 描述层、链式属性层,并初次使用 @State 让按钮点击能改变界面。

从一句装饰器语法说起

现在把工程 pages 目录下的 Index 清空,只留一个空文件,我们一行行手写。声明式 UI 的页面长这样:

@Entry @Component struct Index { build() { Column() { Text('登录') } } }

第一层语法是装饰器。@Component 标记这是一个自定义组件,struct 是它的载体——ArkTS 没有类组件,组件一律是结构体;@Entry 标记它是页面入口,UIAbility 的 loadContent 加载的就是它。没有 @Entry 的组件只能被别的组件引用,不能独立成页(上一节新建 Second 页面时 IDE 自动带上了这两个装饰器,原因在此)。

第二层是 build 方法:每个组件必须且只能有一个 build,返回一段界面描述。注意措辞——是"描述",不是"绘制"。你声明"这里有一个纵向容器,容器里有段文字",至于怎么画,是 ArkUI 框架的事。这就是声明式的核心:界面是数据的函数,你负责说清"是什么",框架负责"怎么变"。

第三层是链式调用:Column()、Text() 这些组件后可以串一串点方法设置属性。下面写完整登录页时会大量出现。

手写登录页

目标:标题、账号与密码输入框、登录按钮;点击按钮时先做本地校验,界面上给出提示文字。完整代码:

@Entry @Component struct Index { @State account: string = '' @State password: string = '' @State tip: string = '' build() { Column({ space: 16 }) { Text('账号登录') .fontSize(28) .fontWeight(FontWeight.Bold) .margin({ top: 60 }) TextInput({ placeholder: '请输入账号' }) .height(48) .onChange((value: string) => { this.account = value }) TextInput({ placeholder: '请输入密码' }) .type(InputType.Password) .height(48) .onChange((value: string) => { this.password = value }) Button('登录') .width('100%') .height(44) .backgroundColor('#007DFF') .onClick(() => { if (this.account.length === 0) { this.tip = '账号不能为空' } else if (this.password.length < 6) { this.tip = '密码至少 6 位' } else { this.tip = '校验通过,准备发起请求' } }) if (this.tip !== '') { Text(this.tip) .fontSize(14) .fontColor('#E8402F') } } .padding(24) .width('100%') .height('100%') .alignItems(HorizontalAlign.Center) } }

逐层拆这段代码:

  • Column({ space: 16 }) 是纵向布局容器,space 控制子元素间距。容器本身在 build 的最外层,说明页面结构"自上而下"。
  • 每个组件的属性都是链式的:fontSize、height、margin 排成一列。链式属性没有顺序要求,但读代码时它们都归属于前一个组件。
  • onChange 与 onClick 是事件回调:输入变化写入变量,点击时读取变量做判断。数据流向清晰——界面变化写入变量,变量变化反过来驱动界面。
  • @State 是本页第一次出现的状态装饰器:account 等变量被 @State 标记后,任何赋值都会触发使用它的界面区域刷新。最后一组 if 就是证据:tip 为空时提示文字不出现在界面上,一旦赋值立即出现。这就是"数据变了界面跟着变"的最小样本,第 4 章会把它扩展成完整的状态管理体系。

图:一个点击在 ArkUI 渲染管线里的旅程

图:一个点击在 ArkUI 渲染管线里的旅程

ArkTS 速成:从 TypeScript 到 ArkTS 的约束

登录页里出现了 TypeScript 的影子(类型标注、箭头函数),这里把用到的部分现场补齐。ArkTS 是 TypeScript 的超集再收紧:变量声明要带类型或可推导,函数参数必须标类型。同时它加了几条硬约束——不能使用 any 与 unknown、不能用解构赋值修改对象属性、组件成员变量不能用某些动态特性。这些约束服务于编译优化:类型确定,方舟运行时才能生成高效代码。

对本页而言只需记住三条:onChange 回调的参数写 (value: string);@State 变量声明时必须给类型与初值;给 this.tip 赋值的箭头函数里的 this 指向组件自身,不要改回普通 function(会丢 this)。

⚠️ 常见坑:把 @State 变量的类型写成联合类型或 any。编译器会直接拒绝。状态变量的类型越具体,框架的依赖分析越精确,这既是约束也是性能提示。

验证与变式

运行工程,按三条路径测试:不填账号点登录——出现红色"账号不能为空";填账号、填短密码——提示切换为"密码至少 6 位";填合规内容——提示"校验通过"。三条路径覆盖了状态驱动的两种典型变化:文字内容变化与元素出现消失。

变式练习两个:其一,把提示文字从底部挪到输入框下方,练习调整组件顺序;其二,加一个"记住账号"的勾选框(Toggle 组件),切换时往 hilog 打一行日志,为第 4 章的状态记录热身。这两个改动都只动 build 内的结构,不需要任何新机制。

本节要点回顾:

  • 三层语法:装饰器定义组件身份,build 描述界面结构,链式调用配置属性与事件。
  • @Entry 与 @Component:页面入口与自定义组件的分工,入口页面必须有 @Entry。
  • @State 初体验:状态变量赋值即触发相关界面刷新,声明式 UI 的发动机,第 4 章的主角。
  • 事件回调:onChange 写入状态,onClick 读取状态做逻辑,数据单向流动。
  • ArkTS 约束:类型必标、any 禁用,约束换来编译期检查与运行时性能。

登录页已经能看、能点、能提示,但它还是一列竖排的控件,谈不上布局。下一章进入组件与布局容器的正题,把这页重排成一个像样的界面,并让同一份代码适配不同大小的屏幕。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U