Vue如何实现验证码输入交互


Posted in Vue.js onDecember 07, 2020

最近做一个H5的页面,里面有个输入验证码交互,就是移动端比较常见的那种验证码输入交互。就是那种,对,就是那种,一个数字一个下划线,移动端非常常见的那种验证码交互。实现过程中主要参考了美团外卖安卓端的具体交互。

应用到项目中的效果如下。

一般操作:

Vue如何实现验证码输入交互

粘贴效果:

Vue如何实现验证码输入交互

方案选择

方案1:调整文字的间距
设置 input 的 letter-spacing 属性,我们就可以让验证码之间有足够大的空隙,然后再把底线改为有间隔的多个线段貌似就可以了。

然而,这里会有一个问题。就是光标总是会在数字的左边,而我们希望的是输入后的数字的中心位于原来光标的位置。最终我放弃了这个方案。

显然,这个方案并不合适。

方案2:使用多个 input
这就是我使用的方式,也是接下来我要详细讲解的方案。主要原理是:使用多个 input 元素,每个 input 只能输入一个数字。当通过 input 事件监测到字符输入时,自动将焦点对焦到下一个 input 元素。

当然我们还要实现点击任何一个输入框时,将焦点移动到第一个value为空的input上。另外,点击退格键时,也要进行焦点的改变。

测试后后发现,焦点的移动,不会导致移动端键盘的收起。最终我就决定使用这个方案了。

代码实现
在线示例:https://codepen.io/F-star/pen/dyyeZaN

HTML:

<div id="app">
 <div class="captcha">
  <input v-for="(c, index) in ct" :key="index"
   type="number" v-model="ct[index]" ref="input" 
   :style="{borderBottomColor: index <= cIndex ? '#333' : ''}"
   @input="e => {onInput(e.target.value, index)}" 
   @keydown.delete="e=>{onKeydown(e.target.value, index)}"
   @focus="onFocus"
   :disabled="loading"
   >
 </div>
 <p>{{msg}}</p>
</div>

CSS:

.captcha {
 display: flex;
 justify-content: center;
 margin-top: 40px;
}
input {
 margin-right: 20px;
 width: 45px;
 text-align: center;
 border: none;
 border-bottom: 1px solid #eee;
 font-size: 24px;
 outline: none;
}
input:last-of-type {
 margin-right: 0;
}
input:disabled {
 color: #000;
 background-color: #fff;
}
.msg {
 text-align: center;
}

JS:

var Main = {
 data() {
  return {
   ct: ['', '', '', '', '', ''],
   loading: false,
   msg: '',
  }
 },
 computed: {
  ctSize() {
   return this.ct.length;
  },
  cIndex() {
   let i = this.ct.findIndex(item => item === '');
   i = (i + this.ctSize) % this.ctSize;
   return i;
  },
  lastCode() {
   return this.ct[this.ctSize - 1];
  }
 },
 watch: {
  cIndex() {
   this.resetCaret();
  },
  lastCode(val) {
   if (val) {
    console.log('this.ctSize', this.ctSize)
    this.$refs.input[this.ctSize - 1].blur();
    this.sendCaptcha();
   }
  }
 },
 mounted() {
  this.resetCaret();
 },
 methods: {
  onInput(val, index) {
   this.msg = ''
   val = val.replace(/\s/g, '');
   if (index == this.ctSize - 1) {
    this.ct[this.ctSize - 1] = val[0];  // 最后一个码,只允许输入一个字符。
   } else if(val.length > 1) {
    let i = index;
    for (i = index; i < this.ctSize && i - index < val.length; i++) {
     this.ct[i] = val[i];
    }
    this.resetCaret();
   }
  },
  // 重置光标位置。
  resetCaret() {
   this.$refs.input[this.ctSize-1].focus();
  },
  onFocus() {
   // 监听 focus 事件,将光标重定位到“第一个空白符的位置”。
   let index = this.ct.findIndex(item => item === '');
   index = (index + this.ctSize) % this.ctSize;
   console.log(this.$refs.input)
   this.$refs.input[index].focus();
  },
  onKeydown(val, index) {
   if (val === '') {
    // 删除上一个input里的值,并对其focus。
    if (index > 0) {
     this.ct[index - 1] = '';
     this.$refs.input[index - 1].focus();
    }
   }
  },
  sendCaptcha() {
   console.log();
   this.msg = `发送验证码到服务器:${this.ct.join('')}`;
   // 此时无法操作 input。。
   this.loading = true;
   setTimeout(() => {
    this.msg = ('验证码错误')
    this.loading = false;
    this.$nextTick(() => {
     this.reset();
    })
   }, 3000)
  },

  reset() {
   // 重置。一般是验证码错误时触发。
   this.ct = this.ct.map(item => '');
   this.resetCaret();
  }
 }
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')

原理

创建多个 input 元素,对这些 input 都绑定 focus 事件。一旦触发该事件,我们会把焦点移动到从左往右第一个 value 为空字符的 input 上。所以在初始状态时,点击最右边的 input,光标还是会跑到最左边的 input。

然后我们给这些 input 绑定 input 事件,监听输入字符。当输入后的字符不为空字符,我们会和 focus 事件一样,重定位下一个需要聚焦的 input。如果输入的是多个字符(一般是是粘贴的缘故),就会把多出来的字符一个一个按顺序填入到后面的 input 中,然后才重定位光标。这样,我们就实现了一个个输入数字和粘贴短信验证码(一次性输入多个数字)的交互。

最后我们还要处理退格行为,需要给所有 input 绑定 keydown 事件。当按下的为退格键,且当前 input 的 value 为空时,清空上一个 input 里的数据,并聚焦到上一个 input 上。

对了,验证码输入错误后,需要清除所有 input 的数据,并把焦点移动到第一个 input 上。

总结
原理并不复,只是实现起来有点繁琐。

我这个方案没有进行浏览器兼容,请大家在经过充分的测试后再行使用。

如果可以的话,我还是推荐简单的一个输入框方案,而不是选择这种花里胡哨的交互。简单稳妥的实现维护简单,也不会有太多意想不到的状况。因为验证码输入这里如果在某些浏览器上无法正确操作,对转化率还是有很大影响的。

以上就是Vue如何实现验证码输入交互的详细内容,更多关于vue 验证码输入交互的资料请关注三水点靠木其它相关文章!

Vue.js 相关文章推荐
浅析VUE防抖与节流
Nov 24 Vue.js
Vue组件生命周期运行原理解析
Nov 25 Vue.js
vue中defineProperty和Proxy的区别详解
Nov 30 Vue.js
vue表单验证之禁止input输入框输入空格
Dec 03 Vue.js
vue基于Echarts的拖拽数据可视化功能实现
Dec 04 Vue.js
解决Vue-cli3没有vue.config.js文件夹及配置vue项目域名的问题
Dec 04 Vue.js
vue实现登录功能
Dec 31 Vue.js
vue element和nuxt的使用技巧分享
Jan 14 Vue.js
Vue 实现可视化拖拽页面编辑器
Feb 01 Vue.js
Vue中插槽slot的使用方法与应用场景详析
Jun 08 Vue.js
vue.js Router中嵌套路由的实用示例
Jun 27 Vue.js
详细聊聊vue中组件的props属性
Nov 02 Vue.js
Vue $attrs &amp; inheritAttr实现button禁用效果案例
Dec 07 #Vue.js
vuex Module将 store 分割成模块的操作
Dec 07 #Vue.js
浅谈Vue使用Elementui修改默认的最快方法
Dec 05 #Vue.js
vue+element_ui上传文件,并传递额外参数操作
Dec 05 #Vue.js
解决vue下载后台传过来的乱码流的问题
Dec 05 #Vue.js
解决Vue-cli3没有vue.config.js文件夹及配置vue项目域名的问题
Dec 04 #Vue.js
vue基于Echarts的拖拽数据可视化功能实现
Dec 04 #Vue.js
You might like
PHP遍历目录并返回统计目录大小
2014/06/09 PHP
PHP7之Mongodb API使用详解
2015/12/26 PHP
支持汉转拼和拼音分词的PHP中文工具类ChineseUtil
2018/02/23 PHP
PHP For循环字母A-Z当超过26个字母时输出AA,AB,AC
2020/02/16 PHP
php设计模式之正面模式实例分析【星际争霸游戏案例】
2020/03/24 PHP
JavaScript 模拟类机制及私有变量的方法及思路
2013/07/10 Javascript
js简单实现让文本框内容逐个字的显示出来
2013/10/22 Javascript
node.js中的querystring.stringify方法使用说明
2014/12/10 Javascript
js中日期的加减法
2015/05/06 Javascript
AngularJS ng-controller 指令简单实例
2016/08/01 Javascript
基于Bootstrap的Metronic框架实现条码和二维码的生成及打印处理操作
2016/08/29 Javascript
详解AngularJS验证、过滤器、指令
2017/01/04 Javascript
JS实现中文汉字按拼音排序的方法
2017/10/09 Javascript
JS实现百度搜索接口及链接功能实例代码
2018/02/02 Javascript
Angular ui-roter 和AngularJS 通过 ocLazyLoad 实现动态(懒)加载模块和依赖
2018/11/25 Javascript
javascript中call()、apply()的区别
2019/03/21 Javascript
javascript 对象 与 prototype 原型用法实例分析
2019/11/11 Javascript
详解微信小程序轨迹回放实现及遇到的坑
2021/02/02 Javascript
python实现的简单RPG游戏流程实例
2015/06/28 Python
在Django同1个页面中的多表单处理详解
2017/01/25 Python
python 接口_从协议到抽象基类详解
2017/08/24 Python
Python实现的多叉树寻找最短路径算法示例
2018/07/30 Python
元组列表字典(莫烦python基础)
2019/04/03 Python
浅谈python多进程共享变量Value的使用tips
2019/07/16 Python
python搜索包的路径的实现方法
2019/07/19 Python
python 如何使用find和find_all爬虫、找文本的实现
2020/10/16 Python
python和C++共享内存传输图像的示例
2020/10/27 Python
Python Selenium库的基本使用教程
2021/01/04 Python
通信工程毕业生自荐信
2013/11/01 职场文书
大学生自助营养快餐店创业计划书
2014/01/13 职场文书
高中军训感言200字
2014/02/23 职场文书
质量月活动策划方案
2014/03/10 职场文书
2014年反洗钱工作总结
2014/11/22 职场文书
学校光盘行动倡议书
2015/04/28 职场文书
观看禁毒宣传片后的感想
2015/08/11 职场文书
使用Python的开发框架Brownie部署以太坊智能合约
2021/05/28 Python