这一段时间做小程序项目,使用的是mpvue的框架,需要自己实现验证码输入,模拟input的光标,上一个框输入后后一个框自动获取焦点,删除时从后往前依次删除。下图是整体效果:
1 <template> 2 <div class="validate-code"> 3 <h3>验证码已发送至</h3> 4 <div class="middle"> 5 <div class="tel">{{telPhone}}</div> 6 <div class="right"> 7 <div class="timer" v-if="timer">({{count}}s)</div> 8 <div class="txt-btn" v-else @click="getCode">重新获取验证码</div> 9 </div> 10 </div> 11 <div class="code-wrap"> 12 <input type="number" 13 placeholder="输入短信验证码" 14 :maxlength="6" 15 placeholder-style="color: #ccc;" 16 @focus="handleFocus" 17 @blur="handleBlur" 18 v-model="validateCode"> 19 <div class="front-wrap" @click="getFocus"> 20 <div class="block"> 21 <i :class="{‘active‘: validateCode.length === 0 && hasFocused}"></i> 22 {{validateArray[0]}} 23 </div> 24 <div class="block"> 25 <i :class="{‘active‘: validateCode.length === 1 && hasFocused}"></i> 26 {{validateArray[1]}} 27 </div> 28 <div class="block"> 29 <i :class="{‘active‘: validateCode.length === 2 && hasFocused}"></i> 30 {{validateArray[2]}} 31 </div> 32 <div class="block"> 33 <i :class="{‘active‘: validateCode.length === 3 && hasFocused}"></i> 34 {{validateArray[3]}} 35 </div> 36 <div class="block"> 37 <i :class="{‘active‘: validateCode.length === 4 && hasFocused}"></i> 38 {{validateArray[4]}} 39 </div> 40 <div class="block"> 41 <i :class="{‘active‘: validateCode.length === 5 && hasFocused}"></i> 42 {{validateArray[5]}} 43 </div> 44 </div> 45 <div class="tips" v-if="errMsg">{{errMsg}}</div> 46 </div> 47 <div class="btn" :class="{‘effective‘: validateCode.length === 6}" @click="bindPhone">登录</div> 48 </div> 49 </template> 50 51 <script> 52 import fly from ‘@/http/config‘ 53 54 export default { 55 components: {}, 56 data () { 57 return { 58 telPhone: ‘‘, 59 validateCode: ‘‘, 60 errMsg: ‘‘, 61 count: 60, 62 timer: null, 63 hasFocused: false 64 } 65 }, 66 computed: { 67 validateArray () { 68 return Array.from(this.validateCode); 69 } 70 }, 71 onShow () { 72 this.errMsg = ‘‘; 73 this.validateCode = ‘‘; 74 }, 75 onReady () { 76 this.telPhone = this.$root.$mp.query.telPhone; 77 this.initTimer(); 78 }, 79 created () { 80 // 81 }, 82 methods: { 83 handleFocus () { 84 this.hasFocused = true; 85 this.errMsg = ‘‘; 86 }, 87 handleBlur() { 88 this.hasFocused = false; 89 }, 90 91 getCode () { 92 if (!this.timer) { 93 this.getBindingVerifyCode() 94 } 95 }, 96 getBindingVerifyCode () { 97 let _this = this 98 fly.get(‘/2c/*********/*******‘, { 99 phoneNum: this.telPhone 100 }).then((data) => { 101 wx.showToast({ 102 title: data.message 103 }) 104 _this.initTimer() 105 }, err => { 106 console.log(err) 107 }) 108 }, 109 bindPhone () { 110 let _this = this; 111 if (this.validateArray.length < 6) { 112 return 113 } 114 fly.get(‘/2c/*****/*******‘, { 115 phoneNum: this.telPhone, 116 verifyCode: this.validateCode 117 }).then((data) => { 118 wx.showToast({ 119 title: data.message 120 }) 121 wx.setStorage({ 122 key: ‘phoneNum‘, 123 data: _this.telPhone 124 }); 125 setTimeout(() => { 126 wx.reLaunch({ 127 url: ‘/pages/index/main‘ 128 }); 129 }, 1000); 130 }, err => { 131 console.log(err); 132 _this.errMsg = err.message; 133 wx.showToast({ 134 icon: ‘none‘, 135 title: err.message 136 }); 137 }) 138 }, 139 initTimer () { 140 let _this = this 141 this.timer = setInterval(() => { 142 if (_this.count <= 0) { 143 _this.count = 60 144 clearInterval(_this.timer) 145 _this.timer = null 146 } 147 _this.$set({ 148 ‘count‘: _this.count 149 }) 150 _this.count-- 151 }, 1000) 152 } 153 } 154 } 155 </script> 156 157 158 <style lang="scss" src="./index.scss"> 159 160 </style>
CSS文件
1 .profile{ 2 width: 100%; 3 height: 100%; 4 background: #f6f6f6; 5 .get-user-info { 6 width: 200px; 7 height: 50px; 8 } 9 .herder{ 10 padding: 25px 10px; 11 background: #f25252; 12 display: flex; 13 justify-content: flex-start; 14 align-items: center; 15 .avatar-wrap{ 16 width: 60px; 17 height: 60px; 18 overflow: hidden; 19 border-radius: 50%; 20 img{ 21 width: 60px; 22 height: 60px; 23 } 24 } 25 .user-info{ 26 color: #fff; 27 margin-left: 10px; 28 display: flex; 29 flex-direction: column; 30 justify-content: center; 31 h5{ 32 font-size: 16px; 33 line-height: 16px; 34 margin-bottom: 10px; 35 } 36 p{ 37 text-indent: 13px; 38 font-size: 14px; 39 line-height: 14px; 40 background: url("../../assets/images/profile/icon_phone.png") 0 50%/9px 14px no-repeat; 41 } 42 } 43 } 44 .content{ 45 .main{ 46 margin: 10px 0; 47 .content-item{ 48 height: 50px; 49 padding: 0 10px; 50 display: flex; 51 background: #fff; 52 justify-content: space-between; 53 align-items: center; 54 border-bottom: 1px solid #f6f6f6; 55 .left{ 56 display: flex; 57 align-items: center; 58 img{ 59 width: 15px; 60 height: 15px; 61 margin-right: 9px; 62 } 63 .title{ 64 font-size: 15px; 65 color: #333; 66 } 67 } 68 .arrow{ 69 display: flex; 70 justify-content: center; 71 align-items: center; 72 .phone{ 73 font-size: 15px; 74 color: #399fda; 75 margin-right: 8px; 76 } 77 img{ 78 width: 6px; 79 height: 9px; 80 } 81 } 82 } 83 } 84 .card-wrap{ 85 background: #fff; 86 padding: 12px 10px; 87 .card{ 88 height: 50px; 89 border-radius: 4px; 90 background: #ffdc69; 91 display: flex; 92 justify-content: space-between; 93 align-items: center; 94 position: relative; 95 .left{ 96 span{ 97 font-size: 15px; 98 color: #884600; 99 line-height: 50px; 100 } 101 img{ 102 width: 34px; 103 height: 31px; 104 margin: 0 5px 0 10px; 105 vertical-align: middle; 106 } 107 } 108 .arrow{ 109 display: flex; 110 justify-content: flex-start; 111 align-items: center; 112 img{ 113 width: 4px; 114 height: 6px; 115 margin: 0 10px 0 3px; 116 } 117 span{ 118 font-size: 13px; 119 color: #884600; 120 } 121 } 122 .icon-fixed{ 123 position: absolute; 124 top: 0; 125 right: 0; 126 width: 27px; 127 height: 27px; 128 } 129 } 130 } 131 } 132 }