/**
|
* CNumberStep
|
* 数字步进器组件,用于在表单中输入数字并通过步进按钮增减数值
|
* 支持设置数值范围、步长、奇偶修正和单位显示
|
* @author Tevin
|
*/
|
|
<template>
|
<view class="c-number-step">
|
<AtInput
|
ref="input"
|
:name="itemRes.name"
|
:title="itemRes.label"
|
:required="itemRes.required"
|
:disabled="itemRes.disabled"
|
:error="itemRes.error"
|
/>
|
<view
|
class="c-number-step-step"
|
:class="[unit?'on-unit':'', isDirty?'':'not-dirty']"
|
ref="number"
|
@tap="evt=>handleOpr()"
|
>
|
<AtInputNumber
|
:min="range[0]"
|
:max="range[1]"
|
:step="step"
|
:width="120"
|
:value="itemRes.formData[itemRes.name] || ''"
|
:onChange="evt => handleChange(evt)"
|
/>
|
<view class="c-number-step-unit">{{unit}}</view>
|
</view>
|
</view>
|
</template>
|
|
<script>
|
import Taro from '@tarojs/taro';
|
import { $ } from '@tarojs/extend';
|
import { AtInput, AtInputNumber } from 'taro-ui-vue';
|
import './cNumberStep.scss';
|
|
export default {
|
name: 'CNumberStep',
|
components: {
|
AtInput,
|
AtInputNumber,
|
},
|
props: {
|
// 表单数据资源(表单组件内部机制专用)
|
itemRes: Object,
|
// 占位提示
|
placeholder: String,
|
// 取值范围
|
range: {
|
type: Array,
|
default: () => [0, 100],
|
},
|
// 步长
|
step: {
|
type: Number,
|
default: 1,
|
},
|
// 奇偶修正 odd 奇数 / even 偶数
|
correct: {
|
type: String,
|
default: '',
|
},
|
// 数值单位
|
unit: {
|
type: String,
|
default: '',
|
},
|
},
|
data() {
|
return {
|
dirty: false,
|
};
|
},
|
computed: {
|
// 脏值检查
|
isDirty() {
|
// 如果已脏
|
if (this.dirty) {
|
return true;
|
}
|
// 未脏时,如果不是无效值也视为脏
|
return !this.isInvalid;
|
},
|
// 是否为无效值
|
isInvalid() {
|
const itemValue = this.itemRes.formData[this.itemRes.name];
|
if (typeof itemValue === 'undefined') {
|
return true;
|
}
|
if (typeof itemValue === 'string' && !itemValue) {
|
return true;
|
}
|
if (typeof itemValue === 'object' && !itemValue) {
|
return true;
|
}
|
return false;
|
},
|
},
|
methods: {
|
handleOpr() {
|
this.dirty = true;
|
if (this.isInvalid) {
|
this.itemRes.onChange(this.range[0]);
|
}
|
},
|
handleChange(val) {
|
this.dirty = true;
|
// 当数值等于边界时,按输入框值处理
|
if (val === this.range[0] || val === this.range[1]) {
|
this._checkInputVal(val);
|
}
|
// 范围内,按普通操作
|
else {
|
// 奇偶修正模式
|
if (this.correct) {
|
const lastValue =
|
this.itemRes.formData[this.itemRes.name] || this.range[0];
|
let nextValue = val;
|
// 奇偶不满足时
|
if (
|
(this.correct === 'odd' && nextValue % 2 === 0) ||
|
(this.correct === 'even' && nextValue % 2 === 1)
|
) {
|
// 如果新值变大,则再增加一次
|
if (lastValue <= nextValue) {
|
// 如果加1没有范围约束,则再次加1
|
if (nextValue + 1 <= this.range[1]) {
|
nextValue++;
|
}
|
// 否则,减1
|
else {
|
nextValue--;
|
}
|
}
|
// 如果新值变小,则再减小一次
|
else if (lastValue > nextValue) {
|
// 如果再减1没有超过约束范围,则再减1
|
if (nextValue - 1 >= this.range[0]) {
|
nextValue--;
|
}
|
// 否则,加1
|
else {
|
nextValue++;
|
}
|
}
|
}
|
// 奇偶满足时
|
else {
|
// 范围约束
|
nextValue = Math.max(nextValue, this.range[0]);
|
nextValue = Math.min(nextValue, this.range[1]);
|
}
|
this.itemRes.onChange(nextValue);
|
}
|
// 正常模式
|
else {
|
this.itemRes.onChange(val);
|
}
|
}
|
},
|
_checkInputVal(realValue) {
|
const $input = $(this.$refs.input.$el).find('.c-number-step-step input');
|
if ($input) {
|
const inputValue = $input.val();
|
// 删除值
|
if (inputValue === '') {
|
this.dirty = false;
|
this.itemRes.onChange('');
|
return;
|
}
|
// 超过边界
|
if (inputValue != realValue) {
|
$input.val(realValue);
|
}
|
}
|
this.itemRes.onChange(realValue);
|
},
|
},
|
mounted() {
|
if (process.env.TARO_ENV === 'h5') {
|
$(this.$refs.input.$el)
|
.find('.at-input__container')
|
.prepend(this.$refs.number.$el);
|
} else if (process.env.TARO_ENV === 'weapp') {
|
$(this.$refs.input.$el)
|
.find('.at-input__container')
|
.append(this.$refs.number);
|
}
|
},
|
};
|
</script>
|