uniapp input 实现验证码输入交互

参考文章:Vue如何实现验证码输入交互

验证码输入,支持复制粘贴

实现效果

html部分:验证码数组循环input输入框,最后一个输入框限制只能输入1个长度的值;输入监听、删除监听、焦点监听

 js部分:

 

 特别注意:uniapp 的 input 组件是封装过的,不是原生input标签,在调用focus,blur事件时,需要这么写:

 可以控制台打印  this.$refs.input[0].$el.childNodes 查看元素结构

 

完整代码

<template>
	<view :style="colorStyle" class="main-page">
		<view v-if="isFirst" class="first-box">
			我们将发送验证码到您的绑定手机:
			<view class="phone">{{phoneComputed}}</view>
			<view class="code-box">
				验证码:
				<input
					v-for="(item, index) in codes"
					:key="index"
					ref="input"
					v-model="codes[index]"
					type="number"
					:maxlength="index === cSize - 1 ? 1 : 6"
					:disabled="loading"
					@input="e => {onInput(e.target.value, index)}"
					@keydown.delete="onKeydown(index)"
					@focus="onFocus" />
				<button class="theme-color code-btn" :disabled="disabled" :class="disabled === true ? 'on' : ''" @click="getCode">
					{{ text }}
				</button>
			</view>
		</view>
		<view v-if="!isFirst" class="second-box">
			<form>
				<view class="form-item">
					输入新密码:
					<input v-model="password" type="text" maxlength="20" password />
				</view>
				<view class="form-item">
					确认新密码:
					<input v-model="confirmPwd" type="text" maxlength="20" password />
				</view>
				<view class="remind-txt">必须是6-20个英文字母、数字或符号(除空格),且字母、数字和标点符号至少包含两种</view>
			</form>
		</view>
		<button class="set-btn-main" hover-class="none" @tap="onSubmit">{{isFirst ? $t('下一步') : $t('确定')}}</button>
	</view>
</template>

<script>
	import colors from '@/mixins/color.js';
	import sendVerifyCode from "@/mixins/SendVerifyCode";
	export default {
		mixins: [colors, sendVerifyCode],
		data() {
			return {
				text: this.$t('获取'),
				isFirst: true,
				loading: false,
				phone: '13741741741',
				codes: ['', '', '', '', '', ''],
				password: '',
				confirmPwd: ''
			}
		},
		computed: {
			phoneComputed () {
				let str = '';
				for (let i=0; i<this.phone.length; i++) {
					if (i > 2 && i < 7) {
						str += '*';
					} else {
						str += this.phone[i];
					}
				}
				return str
			},
			cSize() {
				return this.codes.length;
			},
			cIndex() {
				let i = this.codes.findIndex(item => item === '');
				i = (i + this.cSize) % this.cSize;
				return i;
			},
			lastCode() {
				return this.codes[this.cSize - 1];
			}
		},
		watch: {
			cIndex() {
				this.resetCaret();
			},
			lastCode(val) {
				// 输入最后一位验证码,触发失去焦点并自动校验验证码
				if (val) {
					this.$refs.input[this.cSize - 1].$el.childNodes[0].childNodes[1].blur();
					this.sendCaptcha();
				}
			}
		},
		mounted() {
			console.log(this.$refs.input[0].$el.childNodes)
			this.resetCaret();
		},
		methods: {
			onInput(val, index) {
				val = val.replace(/\s/g, '');
				if (index == this.cSize - 1) {
					// 最后一个码,只允许输入一个字符。
					this.$nextTick(() => {
						this.$set(this.codes, [this.cSize - 1], val[0]);
					})
				} else if(val.length > 1) {
					let i = index;
					for (i = index; i < this.cSize && i - index < val.length; i++) {
						this.codes[i] = val[i];
					}
					this.resetCaret();
				}
			},
			// 重置光标位置。
			resetCaret() {
				this.$refs.input[this.cSize-1].$el.childNodes[0].childNodes[1].focus();
			},
			onFocus() {
				// 监听 focus 事件,将光标重定位到“第一个空白符的位置”。
				let index = this.codes.findIndex(item => item === '');
				index = (index + this.cSize) % this.cSize;
				this.$refs.input[index].$el.childNodes[0].childNodes[1].focus();
			},
			onKeydown(index) {
				let val = this.codes[index];
				if (!val || val === '') {
					// 删除上一个input里的值,并对其focus。
					if (index > 0) {
						this.$nextTick(() => {
							this.$set(this.codes, [index - 1], '');
							this.$refs.input[index - 1].$el.childNodes[0].childNodes[1].focus();
							// 删除上一个input值并移动focus焦点,光标出现在数字左边-尝试用定时器处理(效果不明显)
							// setTimeout(() => {
							// 	this.$refs.input[index - 1].$el.childNodes[0].childNodes[1].focus();
							// }, 100)
						})
					}
				}
			},
			sendCaptcha() {
				console.log('发送验证码到服务器');
				this.$util.Tips({
					title: this.$t(`发送验证码到服务器`)
				});
				// 此时无法操作 input。。
				this.loading = true;
				// 假设验证码错误情况下重置输入框
				setTimeout(() => {
					this.$util.Tips({
						title: this.$t(`验证码错误`)
					});
					this.loading = false;
					this.$nextTick(() => {
						this.reset();
					})
				}, 3000)
			},
			// 重置。一般是验证码错误时触发。
			reset() {
				this.codes = this.codes.map(item => '');
				console.log(this.codes)
				this.resetCaret();
			},
			getCode() {
				this.sendCode();
			},
			onSubmit () {
				this.loading = true;
				if (this.isFirst) {
					if (this.codes.includes('')) {
						return this.$util.Tips({
							title: this.$t(`验证码不正确`)
						});
					}
					this.isFirst = !this.isFirst;
					this.loading = false;
					return
				}
				if (!this.password) {
					return this.$util.Tips({
						title: this.$t(`请输入新密码`)
					});
				}
				if (this.confirmPwd !== this.password) {
					return this.$util.Tips({
						title: this.$t(`确认密码与新密码不一致`)
					});
				}
				let regex = /^(?![\d]+$)(?![a-zA-Z]+$)(?![^\da-zA-Z]+$)([^\u4e00-\u9fa5\s]){6,20}$/;
				if (!regex.test(this.password)) {
					return this.$util.Tips({
						title: this.$t(`密码格式不正确`)
					});
				}
				console.log('提交')
			}
		}
	}
</script>

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值