You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

312 lines
10 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<view class="u-char-box">
<view class="u-char-flex">
<input :disabled="disabledKeyboard" :value="valueModel" type="number" :focus="focus" :maxlength="maxlength" class="u-input" @input="getVal"/>
<view v-for="(item, index) in loopCharArr" :key="index">
<view :class="[breathe && charArrLength == index ? 'u-breathe' : '', 'u-char-item',
charArrLength === index && mode == 'box' ? 'u-box-active' : '',
mode === 'box' ? 'u-box' : '']" :style="{
fontWeight: bold ? 'bold' : 'normal',
fontSize: fontSize + 'rpx',
width: width + 'rpx',
height: width + 'rpx',
color: inactiveColor,
borderColor: charArrLength === index && mode == 'box' ? activeColor : inactiveColor
}">
<view class="u-placeholder-line" :style="{
display: charArrLength === index ? 'block' : 'none',
height: width * 0.5 +'rpx'
}"
v-if="mode !== 'middleLine'"
></view>
<view v-if="mode === 'middleLine' && charArrLength <= index" :class="[breathe && charArrLength == index ? 'u-breathe' : '', charArrLength === index ? 'u-middle-line-active' : '']"
class="u-middle-line" :style="{height: bold ? '4px' : '2px', background: charArrLength === index ? activeColor : inactiveColor}"></view>
<view v-if="mode === 'bottomLine'" :class="[breathe && charArrLength == index ? 'u-breathe' : '', charArrLength === index ? 'u-buttom-line-active' : '']"
class="u-bottom-line" :style="{height: bold ? '4px' : '2px', background: charArrLength === index ? activeColor : inactiveColor}"></view>
<block v-if="!dotFill"> {{ charArr[index] ? charArr[index] : ''}}</block>
<block v-else>
<text class="u-dot">{{ charArr[index] ? '●' : ''}}</text>
</block>
</view>
</view>
</view>
</view>
</template>
<script>
/**
* messageInput 验证码输入框
* @description 该组件一般用于验证用户短信验证码的场景也可以结合uView的键盘组件使用
* @tutorial https://www.uviewui.com/components/messageInput.html
* @property {String Number} maxlength 输入字符个数默认4
* @property {Boolean} dot-fill 是否用圆点填充默认false
* @property {String} mode 模式选择,见上方"基本使用"说明默认box
* @property {String Number} value 预置值
* @property {Boolean} breathe 是否开启呼吸效果见上方说明默认true
* @property {Boolean} focus 是否自动获取焦点默认false
* @property {Boolean} bold 字体和输入横线是否加粗默认true
* @property {String Number} font-size 字体大小单位rpx默认60
* @property {String} active-color 当前激活输入框的样式(默认#2979ff
* @property {String} inactive-color 非激活输入框的样式,文字颜色同此值(默认#606266
* @property {String | Number} width 输入框宽度单位rpx高等于宽默认80
* @property {Boolean} disabled-keyboard 禁止点击输入框唤起系统键盘默认false
* @event {Function} change 输入内容发生改变时触发,具体见官网说明
* @event {Function} finish 输入字符个数达maxlength值时触发见官网说明
* @example <u-message-input mode="bottomLine"></u-message-input>
*/
export default {
name: "u-message-input",
props: {
// 最大输入长度
maxlength: {
type: [Number, String],
default: 4
},
// 是否用圆点填充
dotFill: {
type: Boolean,
default: false
},
// 显示模式box-盒子模式bottomLine-横线在底部模式middleLine-横线在中部模式
mode: {
type: String,
default: "box"
},
// 预置值
value: {
type: [String, Number],
default: ''
},
// 当前激活输入item是否带有呼吸效果
breathe: {
type: Boolean,
default: true
},
// 是否自动获取焦点
focus: {
type: Boolean,
default: false
},
// 字体是否加粗
bold: {
type: Boolean,
default: false
},
// 字体大小
fontSize: {
type: [String, Number],
default: 60
},
// 激活样式
activeColor: {
type: String,
default: '#2979ff'
},
// 未激活的样式
inactiveColor: {
type: String,
default: '#606266'
},
// 输入框的大小单位rpx宽等于高
width: {
type: [Number, String],
default: '80'
},
// 是否隐藏原生键盘如果想用自定义键盘的话需设置此参数为true
disabledKeyboard: {
type: Boolean,
default: false
}
},
watch: {
// maxlength: {
// // 此值设置为true会在组件加载后无需maxlength变化就会执行一次本监听函数无需再created生命周期中处理
// immediate: true,
// handler(val) {
// this.maxlength = Number(val);
// }
// },
value: {
immediate: true,
handler(val) {
// 转为字符串
val = String(val);
// 超出部分截掉
this.valueModel = val.substring(0, this.maxlength);
}
},
},
data() {
return {
valueModel: ""
}
},
computed: {
// 是否显示呼吸灯效果
animationClass() {
return (index) => {
if (this.breathe && this.charArr.length == index) return 'u-breathe';
else return '';
}
},
// 用于显示字符
charArr() {
return this.valueModel.split('');
},
charArrLength() {
return this.charArr.length;
},
// 根据长度循环输入框的个数因为头条小程序数值不能用于v-for
loopCharArr() {
return new Array(this.maxlength);
}
},
methods: {
getVal(e) {
let {
value
} = e.detail
this.valueModel = value;
// 判断长度是否超出了maxlength值理论上不会发生因为input组件设置了maxlength属性值
if (String(value).length > this.maxlength) return;
// 未达到maxlength之前发送change事件达到后发送finish事件
this.$emit('change', value);
if (String(value).length == this.maxlength) {
this.$emit('finish', value);
}
}
}
}
</script>
<style scoped lang="scss">
@import "../../libs/css/style.components.scss";
@keyframes breathe {
0% {
opacity: 0.3;
}
50% {
opacity: 1;
}
100% {
opacity: 0.3;
}
}
.u-char-box {
text-align: center;
}
.u-char-flex {
@include vue-flex;
justify-content: center;
flex-wrap: wrap;
position: relative;
}
.u-input {
position: absolute;
top: 0;
left: -100%;
width: 200%;
height: 100%;
text-align: left;
z-index: 9;
opacity: 0;
background: none;
}
.u-char-item {
position: relative;
width: 90rpx;
height: 90rpx;
margin: 10rpx 10rpx;
font-size: 60rpx;
font-weight: bold;
color: $u-main-color;
line-height: 90rpx;
@include vue-flex;
justify-content: center;
align-items: center;
}
.u-middle-line {
border: none;
}
.u-box {
box-sizing: border-box;
border: 2rpx solid #cccccc;
border-radius: 6rpx;
}
.u-box-active {
overflow: hidden;
animation-timing-function: ease-in-out;
animation-duration: 1500ms;
animation-iteration-count: infinite;
animation-direction: alternate;
border: 2rpx solid $u-type-primary;
}
.u-middle-line-active {
background: $u-type-primary;
}
.u-breathe {
animation: breathe 2s infinite ease;
}
.u-placeholder-line {
/* #ifndef APP-NVUE */
display: none;
/* #endif */
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 2rpx;
height: 40rpx;
background: #333333;
animation: twinkling 1.5s infinite ease;
}
.u-animation-breathe {
animation-name: breathe;
}
.u-dot {
font-size: 34rpx;
line-height: 34rpx;
}
.u-middle-line {
height: 4px;
background: #000000;
width: 80%;
position: absolute;
border-radius: 2px;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.u-buttom-line-active {
background: $u-type-primary;
}
.u-bottom-line {
height: 4px;
background: #000000;
width: 80%;
position: absolute;
border-radius: 2px;
bottom: 0;
left: 50%;
transform: translate(-50%);
}
</style>