Files
cashier_app/pageCreditBuyer/components/number-box.vue

201 lines
3.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="custom-number-box">
<div
class="number-btn number-btn-minus"
:class="{ disabled: isMinDisabled || isDisabled }"
@click="handleMinus"
>
<span>-</span>
</div>
<input
v-model="inputValue"
class="number-input"
type="text"
:disabled="isDisabled"
@input="handleInput"
@blur="handleBlur"
/>
<div
class="number-btn number-btn-plus"
:class="{ disabled: isMaxDisabled || isDisabled }"
@click="handlePlus"
>
<span>+</span>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, watch, computed } from 'vue'
const props = defineProps({
modelValue: {
type: [Number, String],
default: ''
},
min: {
type: Number,
default: 1
},
max: {
type: Number,
default: 28
},
step: {
type: Number,
default: 1
},
disabled: {
type: Boolean,
default: false
},
// ✅ 新增:是否整数(默认 true
integer: {
type: Boolean,
default: true
}
})
const emit = defineEmits(['update:modelValue'])
const inputValue = ref('')
const isDisabled = computed(() => props.disabled)
// 监听外部值
watch(
() => props.modelValue,
(val) => {
if (val === '' || val === null || val === undefined) {
inputValue.value = ''
return
}
const num = Number(val)
inputValue.value = isNaN(num) ? '' : String(num)
},
{ immediate: true }
)
// 减号禁用
const isMinDisabled = computed(() => {
if (inputValue.value === '') return true
const val = Number(inputValue.value)
return val <= props.min
})
// 加号禁用
const isMaxDisabled = computed(() => {
if (inputValue.value === '') return false
const val = Number(inputValue.value)
return val >= props.max
})
// 减
function handleMinus() {
if (inputValue.value === '') return
let val = Number(inputValue.value) - props.step
val = Math.max(val, props.min)
if (props.integer) val = Math.round(val)
inputValue.value = String(val)
emit('update:modelValue', val)
}
// 加
function handlePlus() {
let val
if (inputValue.value === '') {
val = props.min
} else {
val = Number(inputValue.value) + props.step
}
val = Math.min(val, props.max)
if (props.integer) val = Math.round(val)
inputValue.value = String(val)
emit('update:modelValue', val)
}
// 输入时处理
function handleInput() {
let val = inputValue.value.trim()
if (val === '') {
emit('update:modelValue', '')
return
}
// 如果是整数,禁止输入小数点
if (props.integer) val = val.replace(/\./g, '')
const num = Number(val)
if (isNaN(num)) {
inputValue.value = ''
emit('update:modelValue', '')
return
}
inputValue.value = val
emit('update:modelValue', num)
}
// 失焦校验
function handleBlur() {
const val = inputValue.value.trim()
if (val === '') {
emit('update:modelValue', '')
return
}
let num = Number(val)
if (isNaN(num)) {
inputValue.value = ''
emit('update:modelValue', '')
return
}
// 限制范围
num = Math.max(props.min, Math.min(props.max, num))
// ✅ 整数控制
if (props.integer) num = Math.round(num)
inputValue.value = String(num)
emit('update:modelValue', num)
}
</script>
<style scoped>
.custom-number-box {
display: inline-flex;
align-items: center;
border: 1px solid #e4e7ed;
border-radius: 4px;
overflow: hidden;
user-select: none;
}
.number-btn {
width: 36px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
background: #f5f7fa;
cursor: pointer;
font-size: 24px;
}
.number-btn.disabled {
color: #c0c4cc;
cursor: not-allowed;
}
.number-input {
width: 50px;
height: 32px;
text-align: center;
border: none;
outline: none;
font-size: 14px;
padding: 0;
}
</style>