feat: convert number input component to composition API

This commit is contained in:
IchliebedichZhu 2024-03-09 21:01:30 +00:00
parent af2e8b389b
commit e91acafde7

View File

@ -13,11 +13,26 @@
</div> -->
<div v-if="type === 'simple'">
<span class="prepend">{{ prepend }}</span>
<input :class="{ 'small-input': true, disable: !editable }" type="text" :value="modelValue" :readonly="editable ? false : 'readonly'" @input="updateValue($event.target.value)" @focus="focusInput" @blur="blurInput" @keyup="verifyNumber" @keydown="(e) => opNumber(e)" />
<input
:class="{ 'small-input': true, disable: !editable }" type="text" :value="modelValue"
:readonly="!props.editable"
@input="updateValue($event && $event.target ? ($event.target as HTMLInputElement).value : '')"
@focus="focusInput"
@blur="blurInput"
@keyup="verifyNumber"
@keydown="(e) => opNumber(e)" />
</div>
<div v-else class="number-input2">
<div class="input-wrap" @click="edit">
<input :class="{ 'real-input': true, disable: !editable }" type="text" :value="modelValue" :readonly="editable ? false : 'readonly'" @input="updateValue($event.target.value)" @focus="focusInput" @blur="blurInput" @keyup="verifyNumber" @keydown="(e) => opNumber(e)" />
<div class="input-wrap">
<input
:class="{ 'real-input': true, disable: !editable }"
type="text" :value="modelValue" :readonly="!props.editable"
@input="updateValue($event && $event.target ? ($event.target as HTMLInputElement).value : '')"
@focus="focusInput"
@blur="blurInput"
@keyup="verifyNumber"
@keydown="(e) => opNumber(e)"
/>
</div>
<span style="color: rgba(0, 0, 0, 0.45)">{{ label }}</span>
<!-- <div :class="{ 'input-wrap': true, active: inputBorder }">
@ -30,125 +45,130 @@
</div>
</template>
<script>
<script lang="ts" setup>
import { onMounted, ref, watch } from 'vue'
//
const NAME = 'number-input'
// const NAME = 'number-input'
export default {
name: NAME,
props: {
label: {
default: '',
},
modelValue: {
default: '',
},
editable: {
default: true,
},
step: {
default: 1,
},
maxValue: {},
minValue: {},
type: {},
prepend: {},
},
emits: ['finish', 'update:modelValue'],
data() {
return {
inputBorder: false,
tagText: '',
showEdit: false,
type TProps = {
label?: string
modelValue?: string | number
editable?: boolean
step?: number
maxValue?: string | number
minValue?: string | number
type?: string
prepend?: string
}
type TEmits = {
(event: 'finish', data: number | string): void
(event: 'update:modelValue', data: number | string): void
}
const props = withDefaults(defineProps<TProps>(), {
label: '',
modelValue: '',
editable: true,
step: 1
})
const emit = defineEmits<TEmits>()
const inputBorder = ref<boolean>(false)
const tagText = ref<string | number>('')
const showEdit = ref<boolean>(false)
watch(
() => props.modelValue,
() => fixedNum()
)
onMounted(() => {
fixedNum()
})
function fixedNum() {
//
const decimal = String(props.modelValue).split('.')[1]
if (decimal && decimal.length > 2) {
setTimeout(() => {
updateValue(Number(props.modelValue).toFixed(2))
}, 10)
}
//
if (props.maxValue && props.modelValue > props.maxValue) {
setTimeout(() => {
updateValue(Number(props.maxValue))
}, 10)
} else if (typeof props.minValue === 'number' && Number(props.modelValue) < Number(props.minValue)) {
setTimeout(() => {
updateValue(Number(props.minValue))
}, 10)
}
}
function updateValue(value: string | number) {
emit('update:modelValue', value === '-' ? '-' : Number(value))
}
function up() {
updateValue(parseInt(`${props.modelValue}` ?? '0', 10) + props.step)
}
function down() {
let value = parseInt(`${props.modelValue}` ?? '0', 10) - props.step
updateValue(value)
}
function opNumber(e: KeyboardEvent) {
e.stopPropagation()
switch (e.keyCode) {
case 38:
up()
return
case 40:
down()
return
}
}
function verifyNumber() {
let value = String(props.modelValue)
let len = value.length
let newValue = ''
let isNegative = value[0] === '-'
// 0
for (let i = isNegative ? 1 : 0; i < len; ++i) {
let c = value[i]
if (c == '.' || (c >= '0' && c <= '9')) {
newValue += c
} else {
break
}
},
computed: {},
watch: {
modelValue() {
this.fixedNum()
},
},
mounted() {
this.fixedNum()
},
methods: {
fixedNum() {
//
const decimal = String(this.modelValue).split('.')[1]
if (decimal && decimal.length > 2) {
setTimeout(() => {
this.updateValue(Number(this.modelValue).toFixed(2))
}, 10)
}
//
if (this.maxValue && this.modelValue > this.maxValue) {
setTimeout(() => {
this.updateValue(Number(this.maxValue))
}, 10)
} else if (typeof this.minValue === 'number' && this.modelValue < this.minValue) {
setTimeout(() => {
this.updateValue(Number(this.minValue))
}, 10)
}
},
updateValue(value) {
this.$emit('update:modelValue', value === '-' ? '-' : Number(value))
},
up() {
this.updateValue(parseInt(this.modelValue || 0, 10) + this.step)
},
down() {
let value = parseInt(this.modelValue || 0, 10) - this.step
this.updateValue(value)
},
opNumber(e) {
e.stopPropagation()
switch (e.keyCode) {
case 38:
this.up()
return
case 40:
this.down()
return
}
},
verifyNumber() {
let value = String(this.modelValue)
let len = value.length
let newValue = ''
let isNegative = value[0] === '-'
// 0
for (let i = isNegative ? 1 : 0; i < len; ++i) {
let c = value[i]
if (c == '.' || (c >= '0' && c <= '9')) {
newValue += c
} else {
break
}
}
if (newValue === '') {
newValue = '0'
}
if (isNegative) {
newValue = '-' + (newValue === '0' ? '' : newValue)
}
this.updateValue(newValue)
// this.updateValue(parseInt(newValue, 10))
},
focusInput() {
this.inputBorder = true
this.tagText = this.modelValue
},
blurInput() {
if (this.modelValue === '-') {
this.updateValue(0)
}
this.inputBorder = false
if (this.modelValue !== this.tagText) {
this.$emit('finish', this.modelValue)
}
},
},
}
if (newValue === '') {
newValue = '0'
}
if (isNegative) {
newValue = '-' + (newValue === '0' ? '' : newValue)
}
updateValue(newValue)
// this.updateValue(parseInt(newValue, 10))
}
function focusInput() {
inputBorder.value = true
tagText.value = props.modelValue
}
function blurInput() {
if (props.modelValue === '-') {
updateValue(0)
}
inputBorder.value = false
if (props.modelValue !== tagText.value) {
emit('finish', props.modelValue)
}
}
</script>