<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="screen-orientation" content="portrait">
<meta name="full-screen" content="no">
<meta name="x5-orientation" content="portrait">
<meta name="x5-fullscreen" content="false">
<meta name="viewport" content="initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no,width=device-width,viewport-fit=cover">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="format-detection" content="telephone=no">
<title>vue-6格验证码-支持自动填充</title>
<script src="./js/rem.js"></script>
<link rel="stylesheet" href="./css/index.css">
</head>
<body>
<div id="wrapper" v-cloak>
<div class="content">
<h2>{{ this.phone | mobileToStar }}</h2>
<div class="input-box code">
<div class="input-content" @keydown="keydown" @keyup="keyup" @paste="paste" @mousewheel="mousewheel" @input="inputEvent">
<input
ref="firstinput"
v-model.trim.number="input[0]"
class="code-text"
max="9"
min="0"
maxlength="6"
data-index="0"
type="tel"
:class="{'btnLight': iptFocus[1] || input[0]}"
@focus="handleFocus(1)"
@blur="handleBlur(1)"
>
<input v-model.trim.number="input[1]" class="code-text" max="9" min="0" maxlength="6" data-index="1" type="tel" :class="{'btnLight': iptFocus[2] || input[1]}" @focus="handleFocus(2)" @blur="handleBlur(2)">
<input v-model.trim.number="input[2]" class="code-text" max="9" min="0" maxlength="6" data-index="2" type="tel" :class="{'btnLight': iptFocus[3] || input[2]}" @focus="handleFocus(3)" @blur="handleBlur(3)">
<input v-model.trim.number="input[3]" class="code-text" max="9" min="0" maxlength="6" data-index="3" type="tel" :class="{'btnLight': iptFocus[4] || input[3]}" @focus="handleFocus(4)" @blur="handleBlur(4)">
<input v-model.trim.number="input[4]" class="code-text" max="9" min="0" maxlength="6" data-index="4" type="tel" :class="{'btnLight': iptFocus[5] || input[4]}" @focus="handleFocus(5)" @blur="handleBlur(5)">
<input v-model.trim.number="input[5]" class="code-text" max="9" min="0" maxlength="6" data-index="5" type="tel" :class="{'btnLight': iptFocus[6] || input[5]}" @focus="handleFocus(6)" @blur="handleBlur(6)">
</div>
</div>
<div class="form-button">
<button
v-show="showTime"
type="button"
class="btn-submit"
@click="sendCaptcha"
>重新发送</button>
<button
v-show="!showTime"
type="button"
class="btn-submit active"
><span>重新发送({{ count }}s)</span></button>
</div>
</div>
<!-- <Captcha ref="captchaLogin" @complete="handleLogin" />
handleLogin(value) {
this.loginForm.smsCode = value.join('')
},
handleClear() {
this.loginForm.smsCode = ''
this.$refs['captchaLogin'].clear()
this.$refs['captchaLogin'].focus()
},
-->
</div>
<script type="text/javascript" src="https://www.sucainiu.com/themes/cdn/jquery/jquery-1.10.2.js"></script>
<script type="text/javascript" src="./js/vue.min.js"></script>
<script>
// problem: 点击短信通知栏的“复制”后,6位验证码会自动显示在软键盘左上角,点击一下即完成填充,某些 android 手机不生效,这个事件是 inputEvent,是先填充内容再进行处理的,但是输入框的 input maxlength 是1,如果更改该 maxlength 值为6可以实现填充,但是,如果从中间输入,最后一个输入框会输入最多6个值,输入完成后自动填充了最后一个输入框的6个值了。
// 如果有更好的解决办法,欢迎留言交流!
/*
toast 提示:绑定在window上,使用方法:showMessage('提示信息', time)
*/
window.showMessage = function( $msg, $time, callback ) {
$time = $time === 0 ? 0 : ($time || 1000);
var oDiv = document.createElement("div");
oDiv.setAttribute("id", "toastTip");
// var oBody = document.getElementsByClassName('wrapper')[0];
var oBody = document.getElementsByTagName('body')[0];
oBody.append(oDiv);
$('#toastTip').text( $msg );
$('#toastTip').fadeIn();
setTimeout(function() {
callback()
$('#toastTip').fadeOut(function() {
$('#toastTip').remove();
});
}, $time);
}
var mainVM = new Vue({
el: "#wrapper",
data: {
pasteResult: [], // 存放粘贴进来的数字
iptFocus: [],
phone: 18800001111,
smsCode: '',
countryCode: '+86',
showTime: true,
count: '', // 初始化次数
timer: null,
},
filters: {
/**
* @param {string} 18310746666
* @returns {string} 183****6666 前3后4,中间4星
*/
mobileToStar (value) {
if (!value) return null
let reg = '', str = ''
if (!isNaN(value)) value = value.toString()
let len = value.length
if (len === 4) {
reg = /^([A-Za-z0-9]{1})([A-Za-z0-9]{2})([A-Za-z0-9]{1})$/
str = value.replace(reg, '$1**$3')
} else if (len === 5) {
reg = /^([A-Za-z0-9]{1})([A-Za-z0-9]{3})([A-Za-z0-9]{1})$/
str = value.replace(reg, '$1***$3')
} else if (len > 5 && len < 21) { // 隐藏中间4位
var num = Math.floor(len / 2) - 2
str = value.substr(0, num) + '****' + value.substr(num + 4)
} else if (len > 20) {
str = value.substr(0, 6) + '****' + value.substr(len - 6)
}
return str
}
},
computed: {
input() {
return this.pasteResult.length === 6 ? this.pasteResult : ['', '', '', '', '', '']
}
},
mounted() {
document.getElementById('wrapper').style.display = 'block';
// 这里如果是从上一页过来可以使用 session 取出上一页传递过来的 phone
// 可以从上一页发送验证码,也可以在此页面发送验证码
if (this.validMobile()) {
const TIME_COUNT = 60 // 更改倒计时时间
if (!this.timer) {
this.count = TIME_COUNT
this.showTime = false
this.timer = setInterval(() => {
if (this.count > 1 && this.count <= TIME_COUNT) {
this.count--
} else {
this.showTime = true
clearInterval(this.timer) // 清除定时器
this.timer = null
}
}, 1000)
}
}
this.focus()
this.$on('complete', this.handleComplete)
},
methods: {
sendCaptcha() { // 发送验证码
var phonePre = this.countryCode.replace(/^\+/, '')
if (this.validMobile()) {
this.handleClear()
const TIME_COUNT = 60 // 更改倒计时时间
if (!this.timer) {
this.count = TIME_COUNT
this.showTime = false
this.timer = setInterval(() => {
if (this.count > 1 && this.count <= TIME_COUNT) {
this.count--
} else {
this.showTime = true
clearInterval(this.timer) // 清除定时器
this.timer = null
}
}, 1000)
}
}
},
handleComplete(value) {
this.smsCode = value.join('')
if (this.validCaptcha()) {
showMessage('登录', 1800)
}
},
handleClear() {
this.smsCode = ''