当前位置:   article > 正文

HarmonyOS Next 系列之验证码输入组件实现(二)_鸿蒙 自定义验证码多输入框

鸿蒙 自定义验证码多输入框

系列文章目录

HarmonyOS Next 系列之省市区弹窗选择器实现(一)
HarmonyOS Next 系列之验证码输入组件实现(二)



前言

HarmonyOS Next(基于API11) 实现一个验证码输入组件(VerifyCodeInput),不可复制粘贴,输入验证码无光标自动定位到下一格,删除自动定位到前一格,验证码个数可配置。

在这里插入图片描述


一、实现原理

为了解决输入或删除自动移格通过Text组件来显示验证码而非TextInput,键盘输入通过inputMethod.InputMethodController 自绘控件绑定输入法形式进行输入内容监听,最后通过组件本身
onVisibleAreaChange事件判断页面是隐藏(跳转下一页)或者显示(返回)动态控制键盘弹出和隐藏

二、代码实现

VerifyCodeInput.ets

1.定义参数和变量配置

@Component
export default struct VerifyCodeInput {
  //单个输入框高
  @Prop iheight:number|string=48
  //单个输入框宽
  @Prop iwidth:number|string=48
  //验证码字体大小
  @Prop fontsize:number|string='20fp'
  //验证码框个数
  @Prop count:number=6
  //输入法客户端实例
  private inputController: inputMethod.InputMethodController = inputMethod.getController();
  //自绘编辑框配置
  private textConfig: inputMethod.TextConfig = {
    inputAttribute: {
      textInputType: inputMethod.TextInputType.NUMBER, //只能输入数字
      enterKeyType: inputMethod.EnterKeyType.GO
    },
  };
  //用户输入的验证码
  @Link inputCode: string
  //验证码输入框个数数组
  @State countArr: number[] = new Array(this.count??6).fill(' ') //count个空元素数组
  //是否第一次加载
  private isFirst:boolean=true
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

说明:首先定义了一些组件参数如单个输入框宽高、字体大小、输入框个数等和新建输入法实例inputController并设置只能输入数字。

2、自绘控件输入法事件回调设置和事件解绑

 //自绘控件绑定输入法 @params isFocus:是否聚焦拉起键盘
  async onAttachInput(isFocus?:boolean) {
    try {
      //绑定成功默认拉起键盘
      await this.inputController.attach(isFocus??true, this.textConfig);
    }
    catch (e) {
      console.log(JSON.stringify(e))
    }
  }

  //自绘控件解绑输入法
  async onDetachInput() {
    try {
      await this.inputController.detach()
    }
    catch (e) {
      console.log(JSON.stringify(e))
    }

  }

  //绑定输入法输入和删除事件
  onInputEvent() {
    //输入数字
    this.inputController.on("insertText", (text: string) => {
      if (text && this.inputCode.length < this.count && !isNaN(Number(text))) {
        this.inputCode += text;
      }
    })
    //删除数字
    this.inputController.on("deleteLeft", (length: number) => {
      this.inputCode = this.inputCode.substring(0, this.inputCode.length - 1);
    })
  }
  //解除输入法事件
  offInputEvent(){
    this.inputController.off("insertText");
    this.inputController.off("deleteLeft");
  }

  //组件销毁解除所有绑定
  aboutToDisappear() {
    this.offInputEvent()
    this.onDetachInput()
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

说明:此步骤主要是输入法初始化配置和定义输入事件(输入和删除)回调设置,以及解绑以上所有事件

3、验证码输入框布局和输入法绑定与解绑

 build() {
    Column() {
      Row() {
        ForEach(this.countArr, (item: string, index: number) => {
          Text(this.inputCode[index])
            .width(this.iwidth)
            .height(this.iheight)
            .borderRadius('8')
            .backgroundColor('#ECF1F7')
            .fontSize(this.fontsize)
            .fontWeight(500)
            .textAlign(TextAlign.Center)
            .margin({ left: index === 0 ? 0 : 5, right: index === 5 ? 0 : 5 })
            .flexGrow(1)
            .onClick(() => {
              //点击控件重新绑定弹出键盘
              this.onAttachInput()
            })

        }, (item: string, index: number) => index.toString())
      }
      .justifyContent(FlexAlign.SpaceBetween)
      .onVisibleAreaChange([0.0, 1.0], async(isVisible: boolean, currentRatio: number)=>{
        if (isVisible && currentRatio >= 1.0) {//页面显示
          //延迟200ms兼容绑定失效问题
          setTimeout(async()=>{
            try {
              //绑定输入法和设置聚焦状态弹出键盘
              await this.onAttachInput(true)
            }
            catch (e) {
            }
            if(this.isFirst){//首次加载
              //绑定输入事件
              this.onInputEvent()
              this.isFirst=false
            }

          },200)

        }

        if (!isVisible && currentRatio <= 0.0) {//页面隐藏
          //隐藏键盘
          this.onAttachInput(false)
        }

      })

    }.width('100%')
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

说明:绘制count(默认6个)个验证码输入框,首次加载绑定键盘输入事件,并通过onVisibleAreaChange事件来辅助判断页面是否跳转或返回(重新显示页面),页面跳转时候隐藏键盘,页面重现时恢复弹出键盘,这边有个坑,在页面返回时候需要延迟绑定输入法弹否则弹出键盘会有异常。

入参有:
iheight:组件高 number|string
iwidth:组件宽 number|string
count 验证码个数 number 默认值6
value 用户输入的验证码 string 双向绑定值

完整代码:

目录:
在这里插入图片描述

VerifyCodeInput.ets

import { inputMethod } from '@kit.IMEKit';

@Component
export default struct VerifyCodeInput {
  //单个输入框高
  @Prop iheight:number|string=48
  //单个输入框宽
  @Prop iwidth:number|string=48
  //验证码字体大小
  @Prop fontsize:number|string='20fp'
  //验证码框个数
  @Prop count:number=6
  //输入法客户端实例
  private inputController: inputMethod.InputMethodController = inputMethod.getController();
  //自绘编辑框配置
  private textConfig: inputMethod.TextConfig = {
    inputAttribute: {
      textInputType: inputMethod.TextInputType.NUMBER, //只能输入数字
      enterKeyType: inputMethod.EnterKeyType.GO
    },
  };
  //用户输入的验证码
  @Link inputCode: string

  //验证码输入框个数数组
  @State countArr: number[] = new Array(this.count??6).fill(' ') //count个空元素数组
  //是否第一次加载
  private isFirst:boolean=true


  //自绘控件绑定输入法 @params isFocus:是否聚焦拉起键盘
  async onAttachInput(isFocus?:boolean) {
    try {
      //绑定成功默认拉起键盘
      await this.inputController.attach(isFocus??true, this.textConfig);
    }
    catch (e) {
      console.log(JSON.stringify(e))
    }
  }

  //自绘控件解绑输入法
  async onDetachInput() {
    try {
      await this.inputController.detach()
    }
    catch (e) {
      console.log(JSON.stringify(e))
    }

  }

  //绑定输入法输入和删除事件
  onInputEvent() {
    //输入数字
    this.inputController.on("insertText", (text: string) => {
      if (text && this.inputCode.length < this.count && !isNaN(Number(text))) {
        this.inputCode += text;
      }
    })
    //删除数字
    this.inputController.on("deleteLeft", (length: number) => {
      this.inputCode = this.inputCode.substring(0, this.inputCode.length - 1);
    })
  }
  //解除输入法事件
  offInputEvent(){
    this.inputController.off("insertText");
    this.inputController.off("deleteLeft");
  }

  //组件销毁解除所有绑定
  aboutToDisappear() {
    this.offInputEvent()
    this.onDetachInput()
  }


  build() {
    Column() {
      Row() {
        ForEach(this.countArr, (item: string, index: number) => {
          Text(this.inputCode[index])
            .width(this.iwidth)
            .height(this.iheight)
            .borderRadius('8')
            .backgroundColor('#ECF1F7')
            .fontSize(this.fontsize)
            .fontWeight(500)
            .textAlign(TextAlign.Center)
            .margin({ left: index === 0 ? 0 : 5, right: index === 5 ? 0 : 5 })
            .flexGrow(1)
            .onClick(() => {
              //点击控件重新绑定弹出键盘
              this.onAttachInput()
            })

        }, (item: string, index: number) => index.toString())
      }
      .justifyContent(FlexAlign.SpaceBetween)
      .onVisibleAreaChange([0.0, 1.0], async(isVisible: boolean, currentRatio: number)=>{
        if (isVisible && currentRatio >= 1.0) {//页面显示
          //延迟200ms兼容绑定失效问题
          setTimeout(async()=>{
            try {
              //绑定输入法和设置聚焦状态弹出键盘
              await this.onAttachInput(true)
            }
            catch (e) {
            }
            if(this.isFirst){//首次加载
              //绑定输入事件
              this.onInputEvent()
              this.isFirst=false
            }

          },200)

        }

        if (!isVisible && currentRatio <= 0.0) {//页面隐藏
          //隐藏键盘
          this.onAttachInput(false)
        }

      })

    }.width('100%')
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130

页面调用

Index.ets

import VerifyCodeInput from '../components/VerifyCodeInput/VerifyCodeInput'

@Entry
@Component
struct Index {
  //输入的验证码,双向绑定
  @State value:string=''

  build() {
    Navigation() {
      Column() {
        VerifyCodeInput({inputCode:this.value})
      }.width('100%')
    }.title('验证码输入')
    .titleMode(NavigationTitleMode.Mini)
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

效果:
在这里插入图片描述
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/979338
推荐阅读
相关标签
  

闽ICP备14008679号