在移动端应用中,验证码输入是非常常见的交互场景。默认的 TextInput 组件虽然可以完成输入,但在用户体验上存在一些不足:

  • 无法直观显示固定长度的验证码
  • 当前输入位焦点不明显
  • 无法灵活自定义样式

本文将结合鸿蒙 ArkUI(JavaScript/TypeScript) 的能力,分享我自定义验证码输入框的实现方法,支持:

  • 指定位数验证码
  • 当前输入位高亮
  • 输入完成回调
  • 支持重置功能

一、核心思路

实现自定义验证码输入框的关键思路如下:

  1. 数据驱动
    每一位验证码对应一个对象,保存内容和是否被选中状态,通过 @ObservedV2@Local 管理状态变化。
  2. UI 渲染
    • 使用 Row 横向排列每个验证码格子
    • Text 显示每位内容
    • 选中格子高亮显示
  1. 输入逻辑
    • 使用一个透明的 TextInput 接收所有输入
    • 输入变化时,更新每个格子内容
    • 删除时自动回退
    • 完成输入触发回调
  1. 扩展性
    • 支持重置输入框
    • 可自定义颜色、格子大小和间距

二、数据模型

首先定义每位验证码的数据对象:

@ObservedV2
export class InputContentObj {
  id: string = "";
  @Trace content: string = "";
  @Trace isSelected: boolean = false;

  constructor(id: string, content: string) {
    this.id = id;
    this.content = content;
    this.isSelected = false;
  }
}
  • id:格子的唯一标识
  • content:当前格子内容
  • isSelected:是否高亮显示

通过数组 InputContentObj[] 管理整个验证码:

@Local inputCode: InputContentObj[] = [];

三、组件实现

1. 参数和状态

@ComponentV2
export struct ComCodeInputView {
  @Local digit: number = 4; // 验证码位数
  @Local inputCode: InputContentObj[] = []
  textWidth: number = 40
  textInterval: number = 10
  @Local selectedColor: ResourceColor = ComColors.color_product
  @Local defaultColor: ResourceColor = ComColors.color_cccccc
  @Param @Require onCodeChange?: VerifyCodeChangeCallback
  @Param resetFlag: number = 0
  @Local inputViewContent: string = ""
  • digit:验证码位数
  • textWidth / textInterval:格子大小与间距
  • selectedColor / defaultColor:选中和默认颜色
  • onCodeChange:输入完成回调
  • resetFlag:重置标志
  • inputViewContent:绑定到隐藏的 TextInput

2. 初始化和重置

initCode() {
  this.inputCode = [];
  for (let i = 0; i < this.digit; i++) {
    const inputContentObj = new InputContentObj(i.toString(), "");
    inputContentObj.isSelected = (i == 0);
    this.inputCode.push(inputContentObj);
  }
}

@Monitor("resetFlag")
reset() {
  for (let i = 0; i < this.digit; i++) {
    this.inputCode[i].content = "";
    this.inputCode[i].isSelected = (i == 0);
  }
  setTimeout(() => {
    this.inputViewContent = "";
  }, 500);
}
  • initCode:组件显示前初始化数组
  • reset:重置内容并设置首位高亮

3. 渲染 UI

build() {
  Stack({ alignContent: Alignment.Center }) {
    Row({ space: this.textInterval }) {
      ForEach(this.inputCode, (value: InputContentObj, index: number) => {
        Text(value.content)
          .width(this.textWidth)
          .height(this.textWidth)
          .textAlign(TextAlign.Center)
          .border({
            width: 1,
            color: value.isSelected ? this.selectedColor : this.defaultColor,
            radius: 8
          })
          .key(value.id);
      }, (item: InputContentObj) => item.id)
    }

    TextInput({ text: this.inputViewContent })
      .width(this.digit * (this.textWidth + this.textInterval))
      .maxLength(this.digit)
      .key(this.resetFlag.toString())
      .opacity(0)
      .id("ComCodeInputView")
      .onChange((value: string) => this.handleInputChange(value))
      .onAppear(() => focusControl.requestFocus("ComCodeInputView"));
  }.width(Percent.percent_100)
}
  • 每个格子通过 Text 渲染
  • 透明 TextInput 捕获用户输入
  • onAppear 自动聚焦

4. 输入逻辑

handleInputChange(value: string) {
  let codeInput = value.split('');
  const cacheInfo: string[] = [];

  for (let i = 0; i < this.digit; i++) {
    cacheInfo[i] = codeInput[i] || "";
    this.inputCode[i].content = cacheInfo[i];
  }

  const inputResult = this.inputCode.map(item => item.content).join('');
  const inputResultLength = inputResult.length;

  for (let i = 0; i < this.digit; i++) {
    this.inputCode[i].isSelected = (i == inputResultLength);
  }

  this.onCodeChange?.(inputResult, inputResultLength === this.digit);
}
  • 自动更新每个格子
  • 删除时自动回退
  • 判断输入完成并回调

四、效果展示

  • 当前输入格子高亮
  • 删除自动回退
  • 完整输入触发回调

可视化效果示意图:

外部调用:


五、优化与经验

  1. 性能
    避免大量 @Local 频繁变动,可考虑整个数组替换。
  2. 扩展性
    • 可自定义粘贴支持
    • 自定义格子样式、颜色、大小
  1. 兼容性
    • 注意不同屏幕尺寸适配
    • 数字/字母混合输入支持

六、注意事项

在实现控件的过程中,需要特别注意,关于同一个控件由于多个状态值控制导致同一时刻多次刷新,最终导致状态错乱的问题,规避手段如下:

(1)延时部分刷新——本控件目前是这样

(2)刷新对象抽离成一个


七、总结

通过以上方法,我们可以在鸿蒙中快速实现一个 自定义验证码输入框,相比默认组件,用户体验更加直观、友好,并且易于扩展和定制。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐