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

源码:
@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;
})
}
}
复制代码
划线
评论
复制
发布于: 刚刚阅读数: 3
版权声明: 本文为 InfoQ 作者【auhgnixgnahz】的原创文章。
原文链接:【http://xie.infoq.cn/article/458806fd7f0f79cfea412b64c】。文章转载请联系作者。

auhgnixgnahz
关注
还未添加个人签名 2018-07-10 加入
欢迎关注:HarmonyOS开发笔记
评论