这一段时间做小程序项目,使用的是mpvue的框架,需要自己实现验证码输入,模拟input的光标,上一个框输入后后一个框自动获取焦点,删除时从后往前依次删除。下图是整体效果:
<template>
<div class="validate-code">
<h3>验证码已发送至</h3>
<div class="middle">
<div class="tel">{{telPhone}}</div>
<div class="right">
<div class="timer" v-if="timer">({{count}}s)</div>
<div class="txt-btn" v-else @click="getCode">重新获取验证码</div>
</div>
</div>
<div class="code-wrap">
<input type="number"
placeholder="输入短信验证码"
:maxlength="6"
placeholder-style="color: #ccc;"
@focus="handleFocus"
@blur="handleBlur"
v-model="validateCode">
<div class="front-wrap" @click="getFocus">
<div class="block">
<i :class="{'active': validateCode.length === 0 && hasFocused}"></i>
{{validateArray[0]}}
</div>
<div class="block">
<i :class="{'active': validateCode.length === 1 && hasFocused}"></i>
{{validateArray[1]}}
</div>
<div class="block">
<i :class="{'active': validateCode.length === 2 && hasFocused}"></i>
{{validateArray[2]}}
</div>
<div class="block">
<i :class="{'active': validateCode.length === 3 && hasFocused}"></i>
{{validateArray[3]}}
</div>
<div class="block">
<i :class="{'active': validateCode.length === 4 && hasFocused}"></i>
{{validateArray[4]}}
</div>
<div class="block">
<i :class="{'active': validateCode.length === 5 && hasFocused}"></i>
{{validateArray[5]}}
</div>
</div>
<div class="tips" v-if="errMsg">{{errMsg}}</div>
</div>
<div class="btn" :class="{'effective': validateCode.length === 6}" @click="bindPhone">登录</div>
</div>
</template> <script>
import fly from '@/http/config' export default {
components: {},
data () {
return {
telPhone: '',
validateCode: '',
errMsg: '',
count: 60,
timer: null,
hasFocused: false
}
},
computed: {
validateArray () {
return Array.from(this.validateCode);
}
},
onShow () {
this.errMsg = '';
this.validateCode = '';
},
onReady () {
this.telPhone = this.$root.$mp.query.telPhone;
this.initTimer();
},
created () {
//
},
methods: {
handleFocus () {
this.hasFocused = true;
this.errMsg = '';
},
handleBlur() {
this.hasFocused = false;
}, getCode () {
if (!this.timer) {
this.getBindingVerifyCode()
}
},
getBindingVerifyCode () {
let _this = this
fly.get('/2c/*********/*******', {
phoneNum: this.telPhone
}).then((data) => {
wx.showToast({
title: data.message
})
_this.initTimer()
}, err => {
console.log(err)
})
},
bindPhone () {
let _this = this;
if (this.validateArray.length < 6) {
return
}
fly.get('/2c/*****/*******', {
phoneNum: this.telPhone,
verifyCode: this.validateCode
}).then((data) => {
wx.showToast({
title: data.message
})
wx.setStorage({
key: 'phoneNum',
data: _this.telPhone
});
setTimeout(() => {
wx.reLaunch({
url: '/pages/index/main'
});
}, 1000);
}, err => {
console.log(err);
_this.errMsg = err.message;
wx.showToast({
icon: 'none',
title: err.message
});
})
},
initTimer () {
let _this = this
this.timer = setInterval(() => {
if (_this.count <= 0) {
_this.count = 60
clearInterval(_this.timer)
_this.timer = null
}
_this.$set({
'count': _this.count
})
_this.count--
}, 1000)
}
}
}
</script> <style lang="scss" src="./index.scss"> </style>
CSS文件
.profile{
width: 100%;
height: 100%;
background: #f6f6f6;
.get-user-info {
width: 200px;
height: 50px;
}
.herder{
padding: 25px 10px;
background: #f25252;
display: flex;
justify-content: flex-start;
align-items: center;
.avatar-wrap{
width: 60px;
height: 60px;
overflow: hidden;
border-radius: 50%;
img{
width: 60px;
height: 60px;
}
}
.user-info{
color: #fff;
margin-left: 10px;
display: flex;
flex-direction: column;
justify-content: center;
h5{
font-size: 16px;
line-height: 16px;
margin-bottom: 10px;
}
p{
text-indent: 13px;
font-size: 14px;
line-height: 14px;
background: url("../../assets/images/profile/icon_phone.png") 0 50%/9px 14px no-repeat;
}
}
}
.content{
.main{
margin: 10px 0;
.content-item{
height: 50px;
padding: 0 10px;
display: flex;
background: #fff;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #f6f6f6;
.left{
display: flex;
align-items: center;
img{
width: 15px;
height: 15px;
margin-right: 9px;
}
.title{
font-size: 15px;
color: #333;
}
}
.arrow{
display: flex;
justify-content: center;
align-items: center;
.phone{
font-size: 15px;
color: #399fda;
margin-right: 8px;
}
img{
width: 6px;
height: 9px;
}
}
}
}
.card-wrap{
background: #fff;
padding: 12px 10px;
.card{
height: 50px;
border-radius: 4px;
background: #ffdc69;
display: flex;
justify-content: space-between;
align-items: center;
position: relative;
.left{
span{
font-size: 15px;
color: #884600;
line-height: 50px;
}
img{
width: 34px;
height: 31px;
margin: 0 5px 0 10px;
vertical-align: middle;
}
}
.arrow{
display: flex;
justify-content: flex-start;
align-items: center;
img{
width: 4px;
height: 6px;
margin: 0 10px 0 3px;
}
span{
font-size: 13px;
color: #884600;
}
}
.icon-fixed{
position: absolute;
top:;
right:;
width: 27px;
height: 27px;
}
}
}
}
}