You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
231 lines
7.0 KiB
231 lines
7.0 KiB
|
3 years ago
|
<template>
|
||
|
|
<view class="s-code-input" :class="c_class" :style="c_style">
|
||
|
|
<view
|
||
|
|
v-for="(item, index) of list"
|
||
|
|
:key="index"
|
||
|
|
class="s-code-input__item"
|
||
|
|
:style="item_style[index]"
|
||
|
|
>
|
||
|
|
<view
|
||
|
|
v-if="dot && codeValues.length > index"
|
||
|
|
class="s-code-input__item__dot"
|
||
|
|
:style="dot_style"
|
||
|
|
></view>
|
||
|
|
<text v-else class="s-code-input__item__text" :style="text_style">
|
||
|
|
{{ codeValues[index] || "" }}
|
||
|
|
</text>
|
||
|
|
<view
|
||
|
|
v-if="mode === 'line'"
|
||
|
|
class="s-code-input__item__line"
|
||
|
|
:style="line_style"
|
||
|
|
></view>
|
||
|
|
<view
|
||
|
|
v-if="isFocus && codeValues.length === index"
|
||
|
|
:style="cursor_style"
|
||
|
|
class="s-code-input__item__cursor"
|
||
|
|
></view>
|
||
|
|
</view>
|
||
|
|
<input
|
||
|
|
:disabled="disabledKeyboard"
|
||
|
|
type="number"
|
||
|
|
:focus="focus"
|
||
|
|
:value="inputValue"
|
||
|
|
:maxlength="maxlength"
|
||
|
|
class="s-code-input__input"
|
||
|
|
:style="input_style"
|
||
|
|
@input="handleChange"
|
||
|
|
@focus="isFocus = true"
|
||
|
|
@blur="isFocus = false"
|
||
|
|
/>
|
||
|
|
</view>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<script>
|
||
|
|
import componentMixin from '../../mixins/componentMixin';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* s-code-input
|
||
|
|
* @description 用于验证用户短信验证码的场景
|
||
|
|
* @property {Number} maxlength 最大输入长度 (默认 4 )
|
||
|
|
* @property {Boolean} dot 是否用圆点填充 (默认 false )
|
||
|
|
* @property {String} mode 显示模式,box-盒子模式,line-底部横线模式 (默认 'box' )
|
||
|
|
* @property {Boolean} hairline 是否细边框 (默认 false )
|
||
|
|
* @property {String|Number} gutter 字符间的距离 (默认 20 )
|
||
|
|
* @property {String|Number} value 预置值
|
||
|
|
* @property {Boolean} focus 是否自动获取焦点 (默认 false )
|
||
|
|
* @property {Boolean} bold 字体和输入横线是否加粗 (默认 false )
|
||
|
|
* @property {String} color 字体颜色
|
||
|
|
* @property {String|Number} fontSize 字体大小,单位px (默认 36 )
|
||
|
|
* @property {String|Number} size 输入框的大小,宽等于高 (默认 70 )
|
||
|
|
* @property {Boolean} disabledKeyboard 是否隐藏原生键盘,如果想用自定义键盘的话,需设置此参数为true (默认 false )
|
||
|
|
* @property {String} borderColor 边框和线条颜色
|
||
|
|
* @property {String|Number} borderRadius mode等于box时边框圆角 (默认 6 )
|
||
|
|
* @property {Boolean} disabledDot 是否禁止输入"."符号 (默认 true )
|
||
|
|
* @property {String|Object} textStyle 数字样式
|
||
|
|
* @property {String|Object} itemStyle 数字块样式
|
||
|
|
* @property {String|Object} lineStyle 下划线样式
|
||
|
|
* @property {String|Object} dotStyle dot点样式
|
||
|
|
* @property {String|Object} cursorStyle 光标样式
|
||
|
|
* @event {Function} change(value) 输入内容发生改变时触发,具体见上方说明 value:当前输入的值
|
||
|
|
* @event {Function} finish(value) 输入字符个数达maxlength值时触发,见上方说明 value:当前输入的值
|
||
|
|
* @example <s-code-input v-model="value" />
|
||
|
|
*/
|
||
|
|
export default {
|
||
|
|
name: 'SCodeInput',
|
||
|
|
mixins: [componentMixin],
|
||
|
|
props: {
|
||
|
|
maxlength: {
|
||
|
|
type: Number,
|
||
|
|
default: 4,
|
||
|
|
},
|
||
|
|
dot: Boolean,
|
||
|
|
mode: {
|
||
|
|
type: String,
|
||
|
|
default: 'box',
|
||
|
|
},
|
||
|
|
hairline: Boolean,
|
||
|
|
gutter: {
|
||
|
|
type: [String, Number],
|
||
|
|
default: 20,
|
||
|
|
},
|
||
|
|
value: {
|
||
|
|
type: [String, Number],
|
||
|
|
default: '',
|
||
|
|
},
|
||
|
|
focus: Boolean,
|
||
|
|
bold: Boolean,
|
||
|
|
color: String,
|
||
|
|
fontSize: [String, Number],
|
||
|
|
size: [String, Number],
|
||
|
|
disabledKeyboard: Boolean,
|
||
|
|
borderColor: String,
|
||
|
|
borderRadius: {
|
||
|
|
type: [String, Number],
|
||
|
|
default: 6,
|
||
|
|
},
|
||
|
|
disabledDot: {
|
||
|
|
type: Boolean,
|
||
|
|
default: true,
|
||
|
|
},
|
||
|
|
textStyle: [String, Object],
|
||
|
|
itemStyle: [String, Object],
|
||
|
|
lineStyle: [String, Object],
|
||
|
|
dotStyle: [String, Object],
|
||
|
|
cursorStyle: [String, Object],
|
||
|
|
},
|
||
|
|
data: () => ({
|
||
|
|
inputValue: '',
|
||
|
|
isFocus: false,
|
||
|
|
}),
|
||
|
|
computed: {
|
||
|
|
c_class() {
|
||
|
|
return this.$mergeClass({
|
||
|
|
[`s-code-input--${this.mode}`]: this.mode && this.mode !== 'none',
|
||
|
|
's-code-input--dot]': this.dot,
|
||
|
|
}, this.custom_class);
|
||
|
|
},
|
||
|
|
c_style() {
|
||
|
|
return this.$mergeStyle(this.custom_style);
|
||
|
|
},
|
||
|
|
input_style() {
|
||
|
|
return this.$mergeStyle({
|
||
|
|
height: this.$addUnit(this.size),
|
||
|
|
});
|
||
|
|
},
|
||
|
|
list() {
|
||
|
|
return new Array(Number(this.maxlength)).fill(1);
|
||
|
|
},
|
||
|
|
item_style() {
|
||
|
|
const { size, mode, hairline, borderColor, gutter, list } = this;
|
||
|
|
const borderRadius = this.$addUnit(this.borderRadius);
|
||
|
|
return this.list.map((_, index) => {
|
||
|
|
const style = {
|
||
|
|
width: this.$addUnit(size),
|
||
|
|
height: this.$addUnit(size),
|
||
|
|
};
|
||
|
|
if (index > 0) {
|
||
|
|
style.marginLeft = this.$addUnit(gutter);
|
||
|
|
}
|
||
|
|
if (mode === 'box') {
|
||
|
|
style.borderWidth = `${hairline ? 0.5 : 1}px`;
|
||
|
|
style.borderColor = borderColor;
|
||
|
|
if (this.$toPx(gutter) > 0) {
|
||
|
|
style.borderRadius = borderRadius;
|
||
|
|
} else {
|
||
|
|
if (index === 0) {
|
||
|
|
style.borderTopLeftRadius = borderRadius;
|
||
|
|
style.borderBottomLeftRadius = borderRadius;
|
||
|
|
}
|
||
|
|
if (index === list.length - 1) {
|
||
|
|
style.borderTopRightRadius = borderRadius;
|
||
|
|
style.borderBottomRightRadius = borderRadius;
|
||
|
|
}
|
||
|
|
if (index !== list.length - 1) {
|
||
|
|
style.borderRight = 'none';
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return this.$mergeStyle(style, this.itemStyle);
|
||
|
|
});
|
||
|
|
},
|
||
|
|
text_style() {
|
||
|
|
return this.$mergeStyle({
|
||
|
|
fontSize: this.$addUnit(this.fontSize),
|
||
|
|
fontWeight: this.bold ? 'bold' : '',
|
||
|
|
color: this.color,
|
||
|
|
}, this.textStyle);
|
||
|
|
},
|
||
|
|
codeValues() {
|
||
|
|
return String(this.inputValue).split('');
|
||
|
|
},
|
||
|
|
line_style() {
|
||
|
|
const style = {};
|
||
|
|
style.width = this.$addUnit(this.size);
|
||
|
|
style.backgroundColor = this.borderColor;
|
||
|
|
return this.$mergeStyle(style, this.lineStyle);
|
||
|
|
},
|
||
|
|
dot_style() {
|
||
|
|
return this.$mergeStyle(this.dotStyle);
|
||
|
|
},
|
||
|
|
cursor_style() {
|
||
|
|
return this.$mergeStyle({
|
||
|
|
backgroundColor: this.color,
|
||
|
|
}, this.cursorStyle);
|
||
|
|
},
|
||
|
|
},
|
||
|
|
watch: {
|
||
|
|
value: {
|
||
|
|
immediate: true,
|
||
|
|
handler(val) {
|
||
|
|
this.inputValue = String(val).substring(0, this.maxlength);
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
created() {
|
||
|
|
this.isFocus = this.focus;
|
||
|
|
},
|
||
|
|
methods: {
|
||
|
|
handleChange(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双向绑定的值
|
||
|
|
this.$emit('input', value);
|
||
|
|
// 达到用户指定输入长度时,发出完成事件
|
||
|
|
if (String(value).length >= Number(this.maxlength)) {
|
||
|
|
this.$emit('finish', value);
|
||
|
|
}
|
||
|
|
},
|
||
|
|
},
|
||
|
|
};
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<style lang="scss" src="./index.scss"></style>
|