|
|
<template> <view class="u-code-input"> <view class="u-code-input__item" :style="[itemStyle(index)]" v-for="(item, index) in codeLength" :key="index" > <view class="u-code-input__item__dot" v-if="dot && codeArray.length > index" ></view> <text v-else :style="{ fontSize: addUnit(fontSize), fontWeight: bold ? 'bold' : 'normal', color: color }" >{{codeArray[index]}}</text> <view class="u-code-input__item__line" v-if="mode === 'line'" :style="[lineStyle]" ></view> <!-- #ifndef APP-PLUS --> <view v-if="isFocus && codeArray.length === index" :style="{backgroundColor: color}" class="u-code-input__item__cursor"></view> <!-- #endif --> </view> <input :disabled="disabledKeyboard" type="number" :focus="focus" :value="inputValue" :maxlength="maxlength" :adjustPosition="adjustPosition" class="u-code-input__input" @input="inputHandler" :style="{ height: addUnit(size) }" @focus="isFocus = true" @blur="isFocus = false" /> </view> </template>
<script> import { props } from './props'; import { mpMixin } from '../../libs/mixin/mpMixin'; import { mixin } from '../../libs/mixin/mixin'; import { addUnit, getPx } from '../../libs/function/index'; /** * CodeInput 验证码输入 * @description 该组件一般用于验证用户短信验证码的场景,也可以结合uview-plus的键盘组件使用 * @tutorial https://ijry.github.io/uview-plus/components/codeInput.html
* @property {String | Number} maxlength 最大输入长度 (默认 6 ) * @property {Boolean} dot 是否用圆点填充 (默认 false ) * @property {String} mode 显示模式,box-盒子模式,line-底部横线模式 (默认 'box' ) * @property {Boolean} hairline 是否细边框 (默认 false ) * @property {String | Number} space 字符间的距离 (默认 10 ) * @property {String | Number} value 预置值 * @property {Boolean} focus 是否自动获取焦点 (默认 false ) * @property {Boolean} bold 字体和输入横线是否加粗 (默认 false ) * @property {String} color 字体颜色 (默认 '#606266' ) * @property {String | Number} fontSize 字体大小,单位px (默认 18 ) * @property {String | Number} size 输入框的大小,宽等于高 (默认 35 ) * @property {Boolean} disabledKeyboard 是否隐藏原生键盘,如果想用自定义键盘的话,需设置此参数为true (默认 false ) * @property {String} borderColor 边框和线条颜色 (默认 '#c9cacc' ) * @property {Boolean} disabledDot 是否禁止输入"."符号 (默认 true ) * * @event {Function} change 输入内容发生改变时触发,具体见上方说明 value:当前输入的值 * @event {Function} finish 输入字符个数达maxlength值时触发,见上方说明 value:当前输入的值 * @example <u-code-input v-model="value4" :focus="true"></u-code-input> */ export default { name: 'u-code-input', mixins: [mpMixin, mixin, props], data() { return { inputValue: '', isFocus: this.focus } }, watch: { // #ifdef VUE2
value: { // #endif
// #ifdef VUE3
modelValue: { // #endif
immediate: true, handler(val) { // 转为字符串,超出部分截掉
this.inputValue = String(val).substring(0, this.maxlength) } }, }, computed: { // 根据长度,循环输入框的个数,因为头条小程序数值不能用于v-for
codeLength() { return new Array(Number(this.maxlength)) }, // 循环item的样式
itemStyle() { return index => { const style = { width: addUnit(this.size), height: addUnit(this.size) } // 盒子模式下,需要额外进行处理
if (this.mode === 'box') { // 设置盒子的边框,如果是细边框,则设置为0.5px宽度
style.border = `${this.hairline ? 0.5 : 1}px solid ${this.borderColor}` // 如果盒子间距为0的话
if (getPx(this.space) === 0) { // 给第一和最后一个盒子设置圆角
if (index === 0) { style.borderTopLeftRadius = '3px' style.borderBottomLeftRadius = '3px' } if (index === this.codeLength.length - 1) { style.borderTopRightRadius = '3px' style.borderBottomRightRadius = '3px' } // 最后一个盒子的右边框需要保留
if (index !== this.codeLength.length - 1) { style.borderRight = 'none' } } } if (index !== this.codeLength.length - 1) { // 设置验证码字符之间的距离,通过margin-right设置,最后一个字符,无需右边框
style.marginRight = addUnit(this.space) } else { // 最后一个盒子的有边框需要保留
style.marginRight = 0 }
return style } }, // 将输入的值,转为数组,给item历遍时,根据当前的索引显示数组的元素
codeArray() { return String(this.inputValue).split('') }, // 下划线模式下,横线的样式
lineStyle() { const style = {} style.height = this.hairline ? '2px' : '4px' style.width = addUnit(this.size) // 线条模式下,背景色即为边框颜色
style.backgroundColor = this.borderColor return style } }, emits: ["change", 'finish', "update:modelValue"], methods: { addUnit, // 监听输入框的值发生变化
inputHandler(e) { const value = e.detail.value this.inputValue = value // 是否允许输入“.”符号
if(this.disabledDot) { this.$nextTick(() => { this.inputValue = value.replace('.', '') }) } // 未达到maxlength之前,发送change事件,达到后发送finish事件
this.$emit('change', value) // 修改通过v-model双向绑定的值
// #ifdef VUE3
this.$emit("update:modelValue", value); // #endif
// #ifdef VUE2
this.$emit("input", value); // #endif
// 达到用户指定输入长度时,发出完成事件
if (String(value).length >= Number(this.maxlength)) { this.$emit('finish', value) } } } } </script>
<style lang="scss" scoped> @import "../../libs/css/components.scss"; $u-code-input-cursor-width: 1px; $u-code-input-cursor-height: 40%; $u-code-input-cursor-animation-duration: 1s; $u-code-input-cursor-animation-name: u-cursor-flicker;
.u-code-input { @include flex; position: relative; overflow: hidden;
&__item { @include flex; justify-content: center; align-items: center; position: relative;
&__text { font-size: 15px; color: $u-content-color; }
&__dot { width: 7px; height: 7px; border-radius: 100px; background-color: $u-content-color; }
&__line { position: absolute; bottom: 0; height: 4px; border-radius: 100px; width: 40px; background-color: $u-content-color; } /* #ifndef APP-PLUS */ &__cursor { position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); width: $u-code-input-cursor-width; height: $u-code-input-cursor-height; animation: $u-code-input-cursor-animation-duration u-cursor-flicker infinite; } /* #endif */ }
&__input { // 之所以需要input输入框,是因为有它才能唤起键盘
// 这里将它设置为两倍的屏幕宽度,再将左边的一半移出屏幕,为了不让用户看到输入的内容
position: absolute; left: -750rpx; width: 1500rpx; top: 0; background-color: transparent; text-align: left; } } /* #ifndef APP-PLUS */ @keyframes u-cursor-flicker { 0% { opacity: 0; } 50% { opacity: 1; } 100% { opacity: 0; } } /* #endif */
</style>
|