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
vue3.0实现插件封装
Dec 14 Vue.js
vue+elementUI动态增加表单项并添加验证的代码详解
Dec 17 Vue.js
详解为什么Vue中的v-if和v-for不建议一起用
Jan 13 Vue.js
Vue基本指令实例图文讲解
Feb 25 Vue.js
vue使用v-model进行跨组件绑定的基本实现方法
Apr 28 Vue.js
Vue Element UI自定义描述列表组件
May 18 Vue.js
Vue+TypeScript中处理computed方式
Apr 02 Vue.js
vue中控制mock在开发环境使用,在生产环境禁用方式
Apr 06 Vue.js
vue使用localStorage持久性存储实现评论列表
Apr 14 Vue.js
解决vue中provide inject的响应式监听
Apr 19 Vue.js
vue组件vue-esign实现电子签名
Apr 21 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人民币金额数字转中文大写的函数代码
2013/02/27 PHP
php实现telnet功能示例
2014/04/08 PHP
CodeIgniter钩子用法实例详解
2016/01/20 PHP
PHP截取IE浏览器并缩小原图的方法
2016/03/04 PHP
js 强制弹出窗口代码研究-又一款代码
2010/03/20 Javascript
文本框输入时 实现自动提示(像百度、google一样)
2012/04/05 Javascript
JavaScript高级程序设计(第3版)学习笔记4 js运算符和操作符
2012/10/11 Javascript
一个JavaScript处理textarea中的字符成每一行实例
2014/09/22 Javascript
javascript数组去重的六种方法汇总
2015/08/16 Javascript
javascript电商网站抢购倒计时效果实现
2015/11/19 Javascript
探讨JavaScript标签位置的存放与功能有无关系
2016/01/15 Javascript
Bootstrap 附加导航(Affix)插件实例详解
2016/06/01 Javascript
AngularJS通过$http和服务器通信详解
2016/09/21 Javascript
require.js 加载 vue组件 r.js 合并压缩的实例
2016/10/14 Javascript
详解vue与后端数据交互(ajax):vue-resource
2017/03/16 Javascript
jQuery实现返回顶部按钮和scroll滚动功能[带动画效果]
2017/07/05 jQuery
Vue获取页面元素的相对位置的方法示例
2020/02/05 Javascript
JavaScript实现移动端弹窗后禁止滚动
2020/05/25 Javascript
JavaScript实现简单验证码
2020/08/24 Javascript
[44:21]Ti4 循环赛第四日 附加赛NEWBEE vs LGD
2014/07/13 DOTA
Python程序设计入门(1)基本语法简介
2014/06/13 Python
更改Ubuntu默认python版本的两种方法python-&gt; Anaconda
2016/12/18 Python
Python3实现抓取javascript动态生成的html网页功能示例
2017/08/22 Python
Python使用回溯法子集树模板解决爬楼梯问题示例
2017/09/08 Python
tensorflow实现简单的卷积神经网络
2018/05/24 Python
Python基础之文件读取的讲解
2019/02/16 Python
Python实现迪杰斯特拉算法过程解析
2020/09/18 Python
python实现测试工具(一)——命令行发送get请求
2020/10/19 Python
Jones New York官网:美国女装品牌,受白领女性欢迎
2019/11/26 全球购物
下列程序在32位linux或unix中的结果是什么
2015/01/26 面试题
活动邀请函范文
2014/01/19 职场文书
地质灾害防治方案
2014/05/14 职场文书
会计学专业求职信
2014/07/17 职场文书
毕业证委托书范文
2014/09/26 职场文书
委托书的样本
2015/01/28 职场文书
农业项目合作意向书
2015/05/08 职场文书