基于HarmonyOS的表单与校验:输入验证与正则表达式

一、引言

表单是应用收集用户信息的主要方式。无论是登录注册、个人信息填写、搜索筛选,还是设置配置,都离不开表单组件。而表单的核心挑战是数据校验------如何确保用户输入的数据格式正确、内容合法。

HarmonyOS ArkUI 提供了丰富的表单组件(TextInput、TextArea、Checkbox、Radio、Switch 等),结合正则表达式可以实现强大的数据校验能力。本文将以一个清爽蓝白风格的表单页面为主线,深入讲解表单开发与数据校验的核心技能。

二、表单组件概览

2.1 输入类组件

组件 用途 关键属性
TextInput 单行文本输入 type、placeholder
TextArea 多行文本输入 placeholder、maxLength
Search 搜索输入 hint、searchButton
PasswordInput 密码输入 showPasswordIcon

2.2 选择类组件

组件 用途 关键属性
Checkbox 复选 select、selectedColor
Radio 单选 value、checked
Switch 开关 isOn、selectedColor
Slider 滑块 min、max、value
DatePicker 日期选择 start、end

2.3 按钮类组件

组件 用途
Button 普通按钮
LoadingProgress 加载按钮

三、TextInput 详解

3.1 基本用法

typescript 复制代码
TextInput({ placeholder: '请输入用户名', text: this.username })
  .width('100%')
  .height(46)
  .onChange((v: string) => {
    this.username = v;
  })

代码说明:

  • TextInput 构造参数:placeholder 占位提示,text 绑定当前值。
  • .onChange 回调:输入内容变化时触发,参数是当前输入值。

3.2 输入类型

typescript 复制代码
TextInput({ placeholder: '邮箱' })
  .type(InputType.Email)     // 邮箱键盘

TextInput({ placeholder: '手机号' })
  .type(InputType.PhoneNumber) // 数字键盘

TextInput({ placeholder: '密码' })
  .type(InputType.Password)  // 密码输入

TextInput({ placeholder: '数字' })
  .type(InputType.Number)    // 数字键盘

代码说明:

type 属性控制键盘类型和输入限制:

  • InputType.Email:邮箱键盘,带 @ 符号。
  • InputType.PhoneNumber:数字键盘。
  • InputType.Password:密码输入,内容打码显示。
  • InputType.Number:纯数字键盘。

3.3 其他常用属性

typescript 复制代码
TextInput({ placeholder: '输入' })
  .maxLength(20)                    // 最大长度
  .enabled(true)                    // 是否可用
  .showCounter(true)                // 显示字数统计
  .enterKeyType(EnterKeyType.Done)  // 回车键类型
  .onSubmit(() => {                 // 提交回调
    console.info('提交');
  })

四、正则表达式校验

4.1 什么是正则表达式

正则表达式(Regular Expression)是一种描述字符串匹配模式的工具。它用特殊的语法定义"什么样的字符串是合法的",然后用来校验、搜索、替换文本。

4.2 常用正则模式

模式 含义 示例
^...$ 匹配整个字符串 ^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) 必须含数字

4.3 常用校验正则

typescript 复制代码
// 用户名: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]*$/;

代码说明:

  • ^$ 锚定字符串的开始和结束,确保整个字符串匹配。
  • (?=.*[A-Za-z]) 是正向预查,表示"后面必须包含字母"。
  • (?=.*\d) 表示"后面必须包含数字"。
  • 组合使用实现"必须同时包含字母和数字"的复杂校验。

五、实战代码:表单校验页面

下面我们实现一个完整的表单校验页面,包含用户名、邮箱、手机号、密码四个字段的实时校验。

5.1 定义数据结构

typescript 复制代码
interface RuleRow {
  field: string;
  rule: string;
  example: string;
}

代码说明:

RuleRow 接口描述校验规则表格中的一行数据,包含字段名、规则和示例。

5.2 组件状态定义

typescript 复制代码
@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' }
  ];

代码说明:

  • 每个输入字段对应一个值变量和一个错误信息变量。
  • 错误信息变量用于显示校验失败的原因,初始为空字符串表示无错误。
  • rules 数组存储校验规则表格数据。

5.3 校验方法

typescript 复制代码
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. 同步输入值this.username = v 将输入值保存到状态。

  2. 正则校验 :使用 .test(v) 方法测试输入值是否匹配正则表达式,返回布尔值。

  3. 三元表达式:匹配成功则错误信息为空,失败则设置错误提示文字。

  4. 实时校验 :这些方法在 onChange 回调中调用,实现输入即校验的实时反馈。

5.4 提交方法

typescript 复制代码
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. 结果反馈:通过 Toast 提示校验结果。

5.5 表单字段构建器

typescript 复制代码
@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. 参数设计

    • label:字段标签。
    • placeholder:输入占位提示。
    • value:当前输入值。
    • error:错误信息。
    • onInput:输入回调函数(作为参数传入)。
  2. 错误状态样式.border({ width: 1, color: error ? '#FF4757' : '#E1E6ED' }) 根据是否有错误切换边框颜色,有错误显示红色边框。

  3. 错误提示Text(error) 显示错误信息,.height(16) 固定高度,即使无错误也占位,避免布局跳动。

  4. 回调传递onInput 参数是函数类型,在 onChange 中调用,实现了构建器的通用性。

5.6 构建 UI

typescript 复制代码
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(行动召唤)按钮。

typescript 复制代码
      // 校验规则表格
      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' })

代码说明:

校验规则速查表是一个带表头的三列表格:

  • 表头行包含"字段"、"规则"、"示例"三列,使用浅蓝背景突出。
  • 数据行通过 ForEach 渲染,示例列使用蓝色等宽字体。
  • 列宽通过 layoutWeight 控制(1:2:1)。

六、表单校验最佳实践

6.1 实时校验 vs 提交校验

  • 实时校验:输入时即时反馈,体验好,但可能过早报错。
  • 提交校验:提交时统一校验,流程简单。
  • 推荐:结合使用,输入时实时校验格式,提交时统一校验必填。

6.2 校验反馈设计

  • 错误信息清晰明确,指出具体问题。
  • 错误提示位置稳定,避免布局跳动。
  • 使用颜色(红色边框、红色文字)强化错误视觉。

6.3 正则表达式测试

正则表达式容易出错,建议先在测试工具中验证,再应用到代码中。

6.4 空值校验

除了格式校验,还要处理必填字段的空值校验:

typescript 复制代码
validateRequired(v: string): string {
  if (!v.trim()) {
    return '该字段不能为空';
  }
  return '';
}

七、常见问题

7.1 校验不生效

原因 :正则表达式错误,或 .test() 使用不当。

解决 :先在测试工具验证正则,确认 .test() 参数正确。

7.2 错误提示布局跳动

原因:错误信息高度不固定,导致布局变化。

解决 :给错误提示设置固定高度(如 .height(16))。

7.3 密码输入显示明文

原因 :没有设置 .type(InputType.Password)

解决:设置密码输入类型。

八、总结

本文深入讲解了 HarmonyOS 表单与校验技术,通过一个清爽蓝白风格的表单页面实战演示了输入组件、正则校验、实时反馈和提交处理等核心能力。

核心要点回顾:

  1. TextInput 支持多种输入类型(邮箱、手机号、密码等)。
  2. 正则表达式是数据校验的核心工具。
  3. 通过 .test() 方法校验输入值。
  4. 实时校验在 onChange 中触发,提交时统一验证。
  5. 错误反馈使用红色边框和文字强化。
  6. 使用 @Builder 参数化表单字段,实现复用。

表单是收集用户信息的关键,掌握校验技术能构建可靠、友好的表单体验。下一篇我们将讲解 HarmonyOS 数据可视化(Canvas 绘图)。

相关推荐
蓝速科技1 小时前
蓝速科技丨鸿蒙跨芯片兼容方案:破解信创硬件碎片化落地难题
科技·华为·harmonyos
MartinYeung53 小时前
[论文学习]PoisonBench:评估语言模型对投毒偏好数据的脆弱性
人工智能·学习·语言模型
xian_wwq11 小时前
【学习笔记】-深度认知系列-第1讲-AI不是魔法——三句话讲清楚人工智能到底是什么
笔记·学习·深度认知
M78佐菲11 小时前
c语言学习笔记:排序与查找方法整理
linux·c语言·笔记·学习·算法
别动我齐刘海11 小时前
机器人运动控制学习4——状态估计 State Estimation
c++·人工智能·学习·目标检测·机器学习·机器人·自动驾驶
狂云歌12 小时前
2025年读书回顾,AI+游戏+历史
人工智能·学习·游戏
陈皮波比茶12 小时前
git学习
git·学习
梦想不只是梦与想12 小时前
鸿蒙AGC设备管理:设备注册(一)
harmonyos·设备管理·appgallery
Linux-lucky13 小时前
28-Linux学习之旅之Maven与Nexus制品库
linux·运维·学习·nginx·tomcat·maven