表单是应用收集用户信息的主要方式。无论是登录注册、个人信息填写、搜索筛选,还是设置配置,都离不开表单组件。而表单的核心挑战是数据校验——如何确保用户输入的数据格式正确、内容合法。
HarmonyOS ArkUI 提供了丰富的表单组件(TextInput、TextArea、Checkbox、Radio、Switch 等),结合正则表达式可以实现强大的数据校验能力。本文将以一个清爽蓝白风格的表单页面为主线,深入讲解表单开发与数据校验的核心技能。
| 组件 | 用途 | 关键属性 |
|---|---|---|
| TextInput | 单行文本输入 | type、placeholder |
| TextArea | 多行文本输入 | placeholder、maxLength |
| Search | 搜索输入 | hint、searchButton |
| PasswordInput | 密码输入 | showPasswordIcon |
| 组件 | 用途 | 关键属性 |
|---|---|---|
| Checkbox | 复选 | select、selectedColor |
| Radio | 单选 | value、checked |
| Switch | 开关 | isOn、selectedColor |
| Slider | 滑块 | min、max、value |
| DatePicker | 日期选择 | start、end |
| 组件 | 用途 |
|---|---|
| Button | 普通按钮 |
| LoadingProgress | 加载按钮 |
|
1 2 3 4 5 6 |
TextInput({ placeholder: '请输入用户名', text: this.username }) .width('100%') .height(46) .onChange((v: string) => { this.username = v; }) |
代码说明:
|
1 2 3 4 5 6 7 8 |
TextInput({ placeholder: '邮箱' }) .type(InputType.Email) // 邮箱键盘 TextInput({ placeholder: '手机号' }) .type(InputType.PhoneNumber) // 数字键盘 TextInput({ placeholder: '密码' }) .type(InputType.Password) // 密码输入 TextInput({ placeholder: '数字' }) .type(InputType.Number) // 数字键盘 |
代码说明:
type 属性控制键盘类型和输入限制:
|
1 2 3 4 5 6 7 8 |
TextInput({ placeholder: '输入' }) .maxLength(20) // 最大长度 .enabled(true) // 是否可用 .showCounter(true) // 显示字数统计 .enterKeyType(EnterKeyType.Done) // 回车键类型 .onSubmit(() => { // 提交回调 console.info('提交'); }) |
正则表达式(Regular Expression)是一种描述字符串匹配模式的工具。它用特殊的语法定义"什么样的字符串是合法的",然后用来校验、搜索、替换文本。
| 模式 | 含义 | 示例 |
|---|---|---|
| ^...$ | 匹配整个字符串 | ^abc$ 匹配 “abc” |
| \d | 数字 | \d{11} 匹配 11 位数字 |
| \w | 字母/数字/下划线 | \w+ 匹配单词 |
| [a-z] | 小写字母 | [a-z]+ |
| [0-9] | 数字 | [0-9]{3} |
| {n,m} | 重复 n 到 m 次 | {3,12} |
| + | 至少 1 次 | \d+ |
| * | 0 次或多次 | \w* |
| ? | 0 次或 1 次 | a? |
| ` | ` | 或 |
| (?=...) | 正向预查 | (?=.*\d) 必须含数字 |
|
1 2 3 4 5 6 7 8 9 10 11 12 |
// 用户名:3-12 位字母/数字/下划线 const usernameRegex = /^[a-zA-Z0-9_]{3,12}$/; // 邮箱 const emailRegex = /^[\w.-]+@[\w-]+(\.[\w-]+)+$/; // 手机号:11 位大陆手机号 const phoneRegex = /^1[3-9]\d{9}$/; // 密码:6-16 位,必须包含字母和数字 const passwordRegex = /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{6,16}$/; // 身份证号 const idCardRegex = /^\d{17}[\dXx]$/; // URL const urlRegex = /^(https?|ftp):\/\/[^\s/$.?#].[^\s]*$/; |
代码说明:
下面我们实现一个完整的表单校验页面,包含用户名、邮箱、手机号、密码四个字段的实时校验。
|
1 2 3 4 5 |
interface RuleRow { field: string; rule: string; example: string; } |
代码说明:
RuleRow 接口描述校验规则表格中的一行数据,包含字段名、规则和示例。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
@Entry @Component struct FormPage { @State username: string = ''; @State email: string = ''; @State phone: string = ''; @State password: string = ''; @State usernameErr: string = ''; @State emailErr: string = ''; @State phoneErr: string = ''; @State passwordErr: string = ''; @State rules: RuleRow[] = [ { field: '用户名', rule: '3-12 位字母/数字/下划线', example: 'atom_code' }, { field: '邮箱', rule: '标准邮箱格式', example: 'a@b.com' }, { field: '手机号', rule: '11 位大陆手机号', example: '13800138000' }, { field: '密码', rule: '6-16 位含字母和数字', example: 'abc123' } ]; |
代码说明:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
validateUsername(v: string): void { this.username = v; this.usernameErr = /^[a-zA-Z0-9_]{3,12}$/.test(v) ? '' : '用户名需 3-12 位字母/数字/下划线'; } validateEmail(v: string): void { this.email = v; this.emailErr = /^[\w.-]+@[\w-]+(\.[\w-]+)+$/.test(v) ? '' : '邮箱格式不正确'; } validatePhone(v: string): void { this.phone = v; this.phoneErr = /^1[3-9]\d{9}$/.test(v) ? '' : '手机号格式不正确'; } validatePassword(v: string): void { this.password = v; this.passwordErr = /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{6,16}$/.test(v) ? '' : '密码需 6-16 位且包含字母和数字'; } |
代码说明:
四个校验方法结构一致,核心逻辑是:
|
1 2 3 4 5 6 7 8 9 10 11 12 |
submit(): void { this.validateUsername(this.username); this.validateEmail(this.email); this.validatePhone(this.phone); this.validatePassword(this.password); const ok = !this.usernameErr && !this.emailErr && !this.phoneErr && !this.passwordErr; if (ok) { promptAction.showToast({ message: '? 校验通过,提交成功' }); } else { promptAction.showToast({ message: '? 存在校验错误,请检查' }); } } |
代码说明:
submit 方法在点击提交按钮时执行:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
@Builder FormField(label: string, placeholder: string, value: string, error: string, onInput: (v: string) => void) { Column({ space: 6 }) { Text(label) .fontSize(13) .fontWeight(FontWeight.Medium) .fontColor('#2F3542') .alignSelf(ItemAlign.Start) TextInput({ placeholder: placeholder, text: value }) .width('100%') .height(46) .backgroundColor('#F5F7FA') .borderRadius(10) .placeholderColor('#A0A8B4') .border({ width: 1, color: error ? '#FF4757' : '#E1E6ED' }) .onChange((v: string) => { onInput(v); }) Text(error) .fontSize(11) .fontColor('#FF4757') .alignSelf(ItemAlign.Start) .height(16) } .width('100%') .alignItems(HorizontalAlign.Start) } |
代码说明:
FormField 是表单字段的通用构建器,通过参数化实现复用:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
build() { Scroll() { Column({ space: 16 }) { // 顶部标题 Column() { Text('FORM') .fontSize(12) .fontColor('#B3D4FF') .letterSpacing(8) Text('表单与校验') .fontSize(26) .fontWeight(FontWeight.Bold) .fontColor(Color.White) .margin({ top: 6 }) Text('正则表达式 · 实时校验') .fontSize(12) .fontColor('#B3D4FF') .margin({ top: 6 }) } .width('100%') .padding({ top: 48, bottom: 30 }) .backgroundColor('#3B82F6') // 表单区 Column({ space: 4 }) { this.FormField('用户名', '请输入用户名', this.username, this.usernameErr, (v: string) => { this.validateUsername(v); }) this.FormField('邮箱', '请输入邮箱', this.email, this.emailErr, (v: string) => { this.validateEmail(v); }) this.FormField('手机号', '请输入手机号', this.phone, this.phoneErr, (v: string) => { this.validatePhone(v); }) this.FormField('密码', '请输入密码', this.password, this.passwordErr, (v: string) => { this.validatePassword(v); }) } .width('100%') .padding(20) .backgroundColor(Color.White) .borderRadius(16) .shadow({ radius: 8, color: '#22000000', offsetY: 4 }) // 大号提交按钮 Button('提交表单') .width('100%') .height(52) .fontSize(17) .fontWeight(FontWeight.Bold) .fontColor(Color.White) .linearGradient({ angle: 90, colors: [['#3B82F6', 0], ['#6366F1', 1]] }) .borderRadius(26) .shadow({ radius: 14, color: '#553B82F6', offsetY: 4 }) .onClick(() => { this.submit(); }) |
代码说明:
表单区通过 FormField 构建器生成四个字段,每个字段传入对应的状态、错误信息和校验回调。提交按钮使用蓝紫渐变、大圆角,形成醒目的 CTA(行动召唤)按钮。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
// 校验规则表格 Column() { Text('校验规则速查') .fontSize(14) .fontWeight(FontWeight.Bold) .fontColor('#3B82F6') .alignSelf(ItemAlign.Start) .margin({ bottom: 8 }) Row() { Text('字段').layoutWeight(1).fontSize(12).fontWeight(FontWeight.Bold).fontColor('#3B82F6') Text('规则').layoutWeight(2).fontSize(12).fontWeight(FontWeight.Bold).fontColor('#3B82F6') Text('示例').layoutWeight(1).fontSize(12).fontWeight(FontWeight.Bold).fontColor('#3B82F6') } .width('100%') .padding(10) .backgroundColor('#EFF6FF')
ForEach(this.rules, (row: RuleRow) => { Row() { Text(row.field).layoutWeight(1).fontSize(12).fontColor('#2F3542') Text(row.rule).layoutWeight(2).fontSize(11).fontColor('#555555') Text(row.example).layoutWeight(1).fontSize(11).fontColor('#3B82F6').fontFamily('monospace') } .width('100%') .padding(10) .border({ width: { bottom: 1 }, color: '#EFF6FF' }) }) } .width('100%') .padding(16) .backgroundColor('#F8FBFF') .borderRadius(14) .border({ width: 1, color: '#DCE9FB' }) |
代码说明:
校验规则速查表是一个带表头的三列表格:
正则表达式容易出错,建议先在测试工具中验证,再应用到代码中。
除了格式校验,还要处理必填字段的空值校验:
|
1 2 3 4 5 6 |
validateRequired(v: string): string { if (!v.trim()) { return '该字段不能为空'; } return ''; } |
原因:正则表达式错误,或 .test() 使用不当。
解决:先在测试工具验证正则,确认 .test() 参数正确。
原因:错误信息高度不固定,导致布局变化。
解决:给错误提示设置固定高度(如 .height(16))。
原因:没有设置 .type(InputType.Password)。
解决:设置密码输入类型。
本文深入讲解了 HarmonyOS 表单与校验技术,通过一个清爽蓝白风格的表单页面实战演示了输入组件、正则校验、实时反馈和提交处理等核心能力。
核心要点回顾:
表单是收集用户信息的关键,掌握校验技术能构建可靠、友好的表单体验。下一篇我们将讲解 HarmonyOS 数据可视化(Canvas 绘图)。