鸿蒙Next实现验证码输入框

2025-06-27 22:57:09
108次阅读
0个评论

在应用使用手机号登录验证时,通常需要输入手机验证码4位或者6位,今天实现一个验证码输入的功能。以下,提供了2种实现方案: 第一种比较复杂,每个验证码输入框使用了一个TextInput,需要处理每个TextInput输入回调、删除回调,和焦点处理。 1.拦截输入前onWillInsert和删除前onWillDelete的回调函数,修改验证码的数据,将焦点给到为输入的下一个TextInput 2.输入框增加点击事件拦截,点击输入框定位焦点 第二种使用Text显示输入的验证码,在Text上放置了一个透明的TextInput用于接收输入数据,只需要将输入结果,分别显示到每个Text即可 看一下演示效果: 演示.gif 源码:

@Entry
@ComponentV2
struct VerificationCodeInput {
  @Local digit: number = 4; //验证码输入位数
  @Local currentInputIndex: number = 0; //当前输入位置
  @Local code: string[] = []
  @Local code2: string[] = []
  private lastDeleteTime: number = 0
  aboutToAppear(): void {
    this.initCode()
  }
  initCode() {
    this.code = []
    this.code2 = []
    for (let i = 0; i < this.digit; i++) {
      this.code.push('')
      this.code2.push('')
    }
  }
  checkInputState() {
    for (let i = 0; i < this.code.length; i++) {
      if (this.code[i] == '') {
        this.currentInputIndex = i
        setTimeout(() => {
          focusControl.requestFocus(this.currentInputIndex.toString())
        }, 100)
        return
      }
    }
    this.currentInputIndex = this.digit - 1
    setTimeout(() => {
      focusControl.requestFocus(this.currentInputIndex.toString())
      showToast('模拟短信验证码:' + this.code.join(''))
    }, 100)
  }

  build() {
    Column({ space: 10 }) {

      TextInput({ placeholder: '输入验证码' }).type(InputType.Number)
      Row() {
        Text("验证码位数")
        Counter() {
          Text(this.digit.toString())
        }
        .onInc(() => {
          this.digit += 1;
          this.initCode()
        })
        .onDec(() => {
          this.digit -= 1;
          this.initCode()
        })
      }

      Text('方案1')
      Row({ space: 10 }) {
        ForEach(this.code, (value: string, index: number) => {
          InputItemView({
            inputNum: value,
            index: index,
            inputChange: (val: string) => {
              //这里严格限制一下,当为输入切复制输入的内容时数字且和验证码长度相等才能输入
              if (this.currentInputIndex == 0 && val.length == this.digit && /^\d+$/.test(val)) {
                this.code = val.split('')
              }
              if (val.length == 1) {
                this.code[index] = val
              }
              this.checkInputState()
            },
            willDelete: (val: string) => {
              if ((new Date().getTime() - this.lastDeleteTime < 200)) {
                return
              }
              this.lastDeleteTime = new Date().getTime()
              if (val == '' && index > 0) {
                this.code[index-1] = ''
              } else {
                this.code[index] = ''
              }
              this.checkInputState()
            },
            onChange: () => {
              this.checkInputState()
            }
          })
        })
      }
      .onClick(() => {
        this.checkInputState()
      })
      .onTouchIntercept((event: TouchEvent) => {
        return HitTestMode.Block
      })

      Text('方案2')
      Stack({alignContent:Alignment.Center}) {
        Row({ space: 10 }) {
          ForEach(this.code2, (value: string) => {
            Text(value)
              .width(50)
              .height(50)
              .textAlign(TextAlign.Center)
              .border({
                width: 1,
                color: Color.Gray,
                radius: 5
              })

          })
        }
        TextInput({text:this.code2.join('')}).width(this.digit*60)
          .type(InputType.Number)
          .maxLength(this.digit)
          .onChange((value:string) => {
            console.log('onChange: info:' + value)
            this.code2 = []
            for (let i = 0; i < this.digit; i++) {
              this.code2.push('')
            }
            let codeInput = value.split('')
            for (let i = 0; i < codeInput.length; i++) {
              this.code2[i]=codeInput[i]
            }
            if (this.code2.join('').length==this.digit) {
              showToast('验证码:' + this.code2.join(''))
            }
          }).opacity(0)
      }

    }.alignItems(HorizontalAlign.Center)
    .width('100%')
  }
}
//单个输入框
@ComponentV2
struct InputItemView {
  @Require @Param inputNum: string
  @Require @Param index: number
  @Event inputChange: (val: string) => void;
  @Event willDelete: (val: string) => void;
  @Event onChange: () => void;

  build() {
    TextInput({ placeholder: this.inputNum, text: this.inputNum })
      .textAlign(TextAlign.Center)
      .maxLength(1)
      .type(InputType.Number)
      .width(50)
      .height(50)
      .border({
        width: 1,
        color: Color.Gray,
        radius: 5
      })
      .id(this.index.toString())//在将要输入时,触发该回调
      .onWillInsert((info: InsertValue) => {
        console.log('onWillInsert: info:' + info.insertValue)
        this.inputChange(info.insertValue)
        return false
      })
      .onChange((val: string) => {
        console.log('onChange: info:' + val)
        this.onChange()
      })//在将要删除时,触发该回调
      .onWillDelete((info: DeleteValue) => {
        console.log('onWillDelete: info:' + info.deleteValue)
        this.willDelete(info.deleteValue)
        return false;
      })
  }
}
收藏00

登录 后评论。没有帐号? 注册 一个。