使用input(type=number)实现原生app验证码交互

目录

一、前言:

  1.1 背景:

  1.2 web端访问效果:

二、代码

2.1 代码背景:vue3 + ts

2.1.1  css

2.1.2  html

2.1.3  JS

2.2 # 关键点


一、前言:

  1.1 背景

        1.1.1 为了和app的交互保持一致,所以h5和app内嵌h5也需要保持原生验证码输入交互
        1.1.2 为什么使用 type = number 呢,因为在嵌在app内时,需要唤起数字键盘

  1.2 web端访问效果:

二、代码

2.1 代码背景:vue3 + ts

2.1.1  css

.digits {
  margin-top: 12px;
  position: relative;
  margin-bottom: 24px;
}
.digits input {
  position: absolute;
  z-index: -11;
  top: -100px;
  left: 5px;
  outline: none;
  resize: 0;
  border: none;
  opacity: 0;
}
.digits .digits-num p{
  box-sizing: border-box;
  width: 48px;
  height: 48px;
  background-color: pink;
  border: 1px solid #F6F6F6;
  border-radius: 8px;
  color: #000;
  text-align: center;
  font-size: 20px;
  font-weight: 700;
  line-height: 1.4;
  position: relative;
  -webkit-tap-highlight-color: transparent;
}
.digits .digits-num p + p {
  margin-left: 8px;
}

.digits .digits-num .dots span {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background-color: #000;
}
.digits .digits-num .dot1 {
  animation: cursor1 1.2s infinite;
}
.digits .digits-num .dot2 {
  animation: cursor1 1.2s infinite 0.1s;
}
.digits .digits-num .dot3 {
  animation: cursor1 1.2s infinite 0.2s;
}
.digits .digits-num .dot4 {
  animation: cursor1 1.2s infinite 0.3s;
}
.digits .digits-num .dot5 {
  animation: cursor1 1.2s infinite 0.4s;
}
.digits .digits-num .dot6 {
  animation: cursor1 1.2s infinite 0.5s;
}

.digits .digits-num.error p {
  border-color: red;
  color: red;
}
// 模拟光效效果
.digits .active::after {
  content: '';
  position: absolute;
  width: 1px;
  height: 20px;
  background-color: pink;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  margin: auto;
  animation: cursor 0.8s infinite;
}
.digits .error-tips {
  margin-top: 8px;
  color: red;
  font-size: 12px;
  line-height: 140%;
}

@keyframes cursor1 {
  0% {
    opacity: 0.1;
  }
  50% {
    opacity: 0.8;
  }
  100% {
    opacity: 0.1;
  }
}

2.1.2  html

<template>
    <div class="digits">
        <input :maxlength="6" type="number" v-model.number="verifyCode" ref="ndVerifyCode"  @input="handleInputVerifycode" @focus="handleFocusVerifyCode" @blur="handleBlurVerifyCode" @paste="handlePasteVerifyCode">
        <div class="mui-fl-vert digits-num" :class="{'error': !verifyCodeValid}">
          <template v-if="!verifyCodeLoading">
            <p v-for="(item, index) of 6" :key="index" :class="{'mui-fl-central': 1, 'active': verifyCodeActiveIndex === index}" @click="handleClkPreCode()">{{ verifyCode[index] }}</p>
          </template>
          
          <template v-else>
            <p v-for="i of 6" :key="i" class="mui-fl-central dots"><span :class="`dot${i}`"></span></p>
          </template>
        </div>
        <p v-show="!verifyCodeValid" class="error-tips">Verification code incorrect. Please try again.</p>
   </div>
</template>

2.1.3  JS

<script setup lang="ts">
const verifyCode = ref<string>('')
const ndVerifyCode = shallowRef<HTMLInputElement>() 
const verifyCodeActiveIndex = ref() // 光标位置
const verifyCodeValid = ref<boolean>(true) // 验证码或者粘贴内容是否合法
const verifyCodeLoading = ref<boolean>(false)

onMounted(() => {
  // 在app内,自动弹起键盘,android可以,ios由于有安全机制,需要用户手动点击触发
  ndVerifyCode.value?.focus()
})

const verifyLoginQrCode = () => {
    // 校验验证码的逻辑
}

const handleInputVerifycode = () => {
  const inputValue = verifyCode.value.toString().replace(/\s/g, '')
  verifyCode.value = inputValue.toString().replace(/[^\d]/g, '')

  verifyCodeValid.value = true
  verifyCodeActiveIndex.value = verifyCode.value.toString().length
  if (verifyCode.value.toString().length === 6) {
    verifyLoginQrCode()
  }
}

const handleFocusVerifyCode = () => {
  verifyCodeActiveIndex.value = verifyCode.value.length
}

const handleClkPreCode = () => {
  ndVerifyCode.value?.focus()
}

const handleBlurVerifyCode = () => {
  verifyCodeActiveIndex.value = ''
}

const handlePasteVerifyCode = (event: any) => {
  event.preventDefault();
  const clipboardData = event.clipboardData
  const pastedText = clipboardData.getData('text').toString().replace(/\s/g, '')

  if (!/^\d*$/.test(pastedText) || pastedText.length !== 6) {
    verifyCodeValid.value = false

    // 因为input type=number 时,粘贴不合法的内容时,value为'',但是input框上面还显示转译后的内容,导致用户再次输入后,无法正常显示新的验证码,所以使用了先赋值,在使用setTimeout使值为空
    verifyCode.value = '0'
    setTimeout(() => {
      verifyCode.value = ''
      verifyCodeActiveIndex.value = 0
    })
  } else {
    verifyCode.value = pastedText
    verifyLoginQrCode()
  }
}

</script>

2.2 # 关键点

   2.2.1. input type=number 时,处理粘贴逻辑
   2.2.2. 清除获取不到input的value值

const handlePasteVerifyCode = (event: any) => {
  event.preventDefault();
  const clipboardData = event.clipboardData
  const pastedText = clipboardData.getData('text').toString().replace(/\s/g, '')

  if (!/^\d*$/.test(pastedText) || pastedText.length !== 6) {
    verifyCodeValid.value = false
    verifyCode.value = '0'
    setTimeout(() => {
      verifyCode.value = ''
      verifyCodeActiveIndex.value = 0
    })
  } else {
    verifyCode.value = pastedText
    verifyLoginQrCode()
  }
}

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值