赞
踩
具体样式如下图:
具体实现效果如下图:
这个验证码输入框每个都样式和交互逻辑都非常相似,将其提取出作为组件化编写,减少代码冗余,先将单个输入框的样式进行编写
@Component struct codeInputView { code: string keyNo: number keyStr: string build() { Row() { Column() { TextInput({text: this.code}) .backgroundColor($r('app.color.smart_F5F5F5')) .maxLength(1) .type(InputType.Number) .align(Alignment.Center) .width((screenWidthPxToVp - 87)/6 - 10) } .width((screenWidthPxToVp - 87)/6) } .height(55) .backgroundColor($r('app.color.smart_F5F5F5')) .borderRadius(8) } }
通过查阅开发文档和相关资料,发现可以将focusControl和key配合使用进行切换聚焦组件,切换焦点
// 自定义输入框组件 @Component struct codeInputView { @State code:string keyNo: number keyStr: string // 将code值传递到外部 transfer: (number) => void // 登录请求回调 requestAction?: ()=>void build() { Row() { Column() { TextInput({text: this.code}) .backgroundColor($r('app.color.smart_F5F5F5')) .maxLength(1) .type(InputType.Number) .align(Alignment.Center) .width((screenWidthPxToVp - 87)/6 - 10) .onChange((value) => { if (value.length == 1) { // 当输入框中有验证码输入 // 当不是最后一个输入框时,焦点跳转到下一个输入框 if (this.keyNo != 5) { // 验证码赋值 this.code = value // 验证码传递至外部 this.transfer(value) // 切换焦点到下一个输入框 let nextKeyNo: number = this.keyNo + 1 let nextKeyStr = 'code' + nextKeyNo Log.info('nextKeyStr = ' + nextKeyStr) focusControl.requestFocus(nextKeyStr) } else { // 当最后一个输入框时,传值并且进行登录请求回调 this.transfer(value) this.requestAction() } } }) .onFocus(() => { // 获取焦点时进行日志打印查看 Log.info('get focus = ' + this.keyStr) }) // 设置输入框key值 .key(this.keyStr) } .width((screenWidthPxToVp - 87)/6) } .height(55) .backgroundColor($r('app.color.smart_F5F5F5')) .borderRadius(8) } } // 页面代码 @Entry @Component export default struct VerifyLoginPage { private inputVerify: string = '请输入验证码' private hadSentToPhone: string = '已发送验证码到您的手机号' private code0: string private code1: string private code2: string private code3: string private code4: string private code5: string @State phone: string = '' onPageShow() { this.phone = router.getParams()?.['phone'] } build() { Flex({direction: FlexDirection.Column, alignItems: ItemAlign.Start}) { Image($r('app.media.back_icon')) .size({width: 33, height: 33}) .onClick(() => { Log.info('click back button') router.back() }) Text(this.inputVerify) .textStyle(25, $r('app.color.smart_24292B'), FontWeight.Medium) .margin({top: 32}) Text(this.hadSentToPhone + this.phone) .textStyle(14, $r('app.color.smart_9DA2A5'), FontWeight.Regular) .margin({top: 12}) // 验证码输入框 Flex({direction: FlexDirection.Row, alignItems: ItemAlign.Start, justifyContent: FlexAlign.SpaceBetween}) { codeInputView({keyNo: 0, keyStr: 'code0', transfer: (num)=>{this.code0 = num}}) codeInputView({keyNo: 1, keyStr: 'code1', transfer: (num)=>{this.code1 = num}}) .margin({left: 11}) codeInputView({keyNo: 2, keyStr: 'code2', transfer: (num)=>{this.code2 = num}}) .margin({left: 11}) codeInputView({keyNo: 3, keyStr: 'code3', transfer: (num)=>{this.code3 = num}}) .margin({left: 11}) codeInputView({keyNo: 4, keyStr: 'code4', transfer: (num)=>{this.code4 = num}}) .margin({left: 11}) codeInputView({keyNo: 5, keyStr: 'code5', transfer: (num)=>{this.code5 = num}, requestAction: ()=>{this.loginRequest()}}) .margin({left: 11}) } .margin({top: 80}) } .width('100%') .padding({left: 16, right: 16}) } // 登录请求 loginRequest() { let code = this.code0 + this.code1 + this.code2 + this.code3 + this.code4 + this.code5 Log.info('phone = ' + this.phone) Log.info('code = ' + code) // 登录网络请求 // xxxxxxx }
此时,可以实现当输入后,光标可以跳转至下一个输入框中,并且可以将输入的code传递至组件外部进行存储在页面中
通过日志打印发现,输入删除按钮,onChange方法无法获取到删除的value值。于是通过查看开发文档,发现可以通过onKeyEvent(event: KeyEvent) => {}方法,获取到删除指令,并且通过打印日志发现,每次点击删除按键,都会执行两次删除方法。
这在一开始非常奇怪和难受,因为我想用同样key的值递减来控制光标的移动,而每次删除时,都会往前跳两个输入框,并且输入框的内容不会删除,所以由此我想到可以一次删除方法来进行光标跳转,一次删除方法用来删除输入框的内容。
以下为更新后最终代码
@Component struct codeInputView { @State code: string = '' keyNo: number keyStr: string transfer: (number) => void requestAction?: ()=>void build() { Row() { Column() { TextInput({text: this.code}) .backgroundColor($r('app.color.smart_F5F5F5')) .maxLength(1) .type(InputType.Number) .align(Alignment.Center) .width((screenWidthPxToVp - 87)/6 - 10) .onChange((value) => { if (value.length == 1) { if (this.keyNo != 5) { let nextKeyNo: number = this.keyNo + 1 let nextKeyStr = 'code' + nextKeyNo Log.info('nextKeyStr = ' + nextKeyStr) this.code = value this.transfer(value) focusControl.requestFocus(nextKeyStr) } else { this.transfer(value) this.requestAction() } } }) .onFocus(() => { Log.info('get focus = ' + this.keyStr) Log.info('thisCode = ' + this.code) }) // 删除验证码时执行的方法回调 .onKeyEvent((event: KeyEvent) => { if (event.keyCode == KeyCode.KEYCODE_DEL) { // 当code值不为空时,删除code值 if (this.code != '') { this.code = '' } else if (this.keyNo > 0) { // 如果不是第一个输入框,则每次递减keyNo使光标进行跳转至前一个输入框内 let preKeyNo: number = this.keyNo - 1 let preKeyStr = 'code' + preKeyNo Log.info('preKeyStr = ' + preKeyStr) focusControl.requestFocus(preKeyStr) } } }) .key(this.keyStr) } .width((screenWidthPxToVp - 87)/6) } .height(55) .backgroundColor($r('app.color.smart_F5F5F5')) .borderRadius(8) } } // 页面代码 // 页面代码与第2点相同,在此不过多赘述
此次在codeInputView组件的初始化中code值有进行修改,添加了’'空字符串,这是因为通过打印日志发现,如果不进行赋值的初始化时,code值会为undefined,这个在删除code值时会非常奇怪,所以进行了设空字符串进行初始化
当前HarmonyOs仍在初步学习过程中,大家如果感兴趣或者有问题可以一起沟通交流,目前在学习过程中也遇到一些HarmonyOs开发组件上的一些小bug,希望华为可以及时进行更新修复!努力并大步的发展我们国家自己的移动端系统,遥遥领先!
如果该文章对你有所帮助的话,可以点赞、收藏并关注一下!后续会持续更新更多技术内容
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。