mirror of
https://gitee.com/wot-design-uni/wot-design-uni.git
synced 2025-12-06 17:18:40 +08:00
fix: 🐛 修复 InputNumber 微信小程序设置了precision后无法输入小数点的问题 (#902)
✅ Closes: #878
This commit is contained in:
parent
604faebf4b
commit
e3a03b1dbb
@ -22,7 +22,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</demo-block>
|
</demo-block>
|
||||||
<demo-block title="设置小数精度">
|
<demo-block title="设置小数精度">
|
||||||
<wd-input-number v-model="value6" @change="handleChange6" :precision="2" :step="0.1" />
|
<wd-input-number v-model="value6" @change="handleChange6" :precision="1" :step="0.1" />
|
||||||
</demo-block>
|
</demo-block>
|
||||||
<demo-block title="输入严格为步数的倍数">
|
<demo-block title="输入严格为步数的倍数">
|
||||||
<wd-input-number v-model="value7" @change="handleChange7" step-strictly :step="2" />
|
<wd-input-number v-model="value7" @change="handleChange7" step-strictly :step="2" />
|
||||||
@ -49,7 +49,7 @@ const value2 = ref<number>(1)
|
|||||||
const value3 = ref<number>(1)
|
const value3 = ref<number>(1)
|
||||||
const value4 = ref<number>(2)
|
const value4 = ref<number>(2)
|
||||||
const value5 = ref<number>(1)
|
const value5 = ref<number>(1)
|
||||||
const value6 = ref<string>('1.205')
|
const value6 = ref<string>('1.2')
|
||||||
const value7 = ref<number>(1)
|
const value7 = ref<number>(1)
|
||||||
const value8 = ref<number>(2)
|
const value8 = ref<number>(2)
|
||||||
const value9 = ref<string>('')
|
const value9 = ref<string>('')
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* @Author: weisheng
|
* @Author: weisheng
|
||||||
* @Date: 2024-03-15 20:40:34
|
* @Date: 2024-03-15 20:40:34
|
||||||
* @LastEditTime: 2025-02-11 18:38:54
|
* @LastEditTime: 2025-02-19 12:47:54
|
||||||
* @LastEditors: weisheng
|
* @LastEditors: weisheng
|
||||||
* @Description:
|
* @Description:
|
||||||
* @FilePath: /wot-design-uni/src/uni_modules/wot-design-uni/components/wd-input-number/types.ts
|
* @FilePath: /wot-design-uni/src/uni_modules/wot-design-uni/components/wd-input-number/types.ts
|
||||||
@ -10,8 +10,27 @@
|
|||||||
import type { PropType } from 'vue'
|
import type { PropType } from 'vue'
|
||||||
import { baseProps, makeBooleanProp, makeNumberProp, makeNumericProp, makeRequiredProp, makeStringProp, numericProp } from '../common/props'
|
import { baseProps, makeBooleanProp, makeNumberProp, makeNumericProp, makeRequiredProp, makeStringProp, numericProp } from '../common/props'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 输入框值变化前的回调函数类型定义
|
||||||
|
* @param value 输入框的新值
|
||||||
|
* @returns 返回布尔值或Promise<boolean>,用于控制是否允许值的变化
|
||||||
|
*/
|
||||||
export type InputNumberBeforeChange = (value: number | string) => boolean | Promise<boolean>
|
export type InputNumberBeforeChange = (value: number | string) => boolean | Promise<boolean>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 输入数字组件事件类型枚举
|
||||||
|
* Input: 用户输入事件
|
||||||
|
* Blur: 失焦事件
|
||||||
|
* Watch: 监听值变化事件
|
||||||
|
* Button: 按钮点击事件
|
||||||
|
*/
|
||||||
|
export enum InputNumberEventType {
|
||||||
|
Input = 'input',
|
||||||
|
Blur = 'blur',
|
||||||
|
Watch = 'watch',
|
||||||
|
Button = 'button'
|
||||||
|
}
|
||||||
|
|
||||||
export const inputNumberProps = {
|
export const inputNumberProps = {
|
||||||
...baseProps,
|
...baseProps,
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -42,21 +42,25 @@ export default {
|
|||||||
import wdIcon from '../wd-icon/wd-icon.vue'
|
import wdIcon from '../wd-icon/wd-icon.vue'
|
||||||
import { computed, nextTick, ref, watch } from 'vue'
|
import { computed, nextTick, ref, watch } from 'vue'
|
||||||
import { isDef, isEqual } from '../common/util'
|
import { isDef, isEqual } from '../common/util'
|
||||||
import { inputNumberProps } from './types'
|
import { inputNumberProps, InputNumberEventType } from './types'
|
||||||
import { callInterceptor } from '../common/interceptor'
|
import { callInterceptor } from '../common/interceptor'
|
||||||
|
|
||||||
const props = defineProps(inputNumberProps)
|
const props = defineProps(inputNumberProps)
|
||||||
const emit = defineEmits(['focus', 'blur', 'change', 'update:modelValue'])
|
const emit = defineEmits(['focus', 'blur', 'change', 'update:modelValue'])
|
||||||
const inputValue = ref<string | number>(getInitValue()) // 输入框的值
|
const inputValue = ref<string | number>(getInitValue()) // 输入框的值
|
||||||
|
|
||||||
// 减号是否禁用
|
/**
|
||||||
|
* 判断数字是否达到最小值限制
|
||||||
|
*/
|
||||||
const minDisabled = computed(() => {
|
const minDisabled = computed(() => {
|
||||||
const value = formatValue(inputValue.value)
|
const value = formatValue(inputValue.value)
|
||||||
const { disabled, min, step } = props
|
const { disabled, min, step } = props
|
||||||
return disabled || Number(value) <= min || changeStep(value, -step) < min
|
return disabled || Number(value) <= min || changeStep(value, -step) < min
|
||||||
})
|
})
|
||||||
|
|
||||||
// 加号是否禁用
|
/**
|
||||||
|
* 判断数字是否达到最大值限制
|
||||||
|
*/
|
||||||
const maxDisabled = computed(() => {
|
const maxDisabled = computed(() => {
|
||||||
const value = formatValue(inputValue.value)
|
const value = formatValue(inputValue.value)
|
||||||
const { disabled, max, step } = props
|
const { disabled, max, step } = props
|
||||||
@ -67,17 +71,22 @@ const maxDisabled = computed(() => {
|
|||||||
watch(
|
watch(
|
||||||
() => props.modelValue,
|
() => props.modelValue,
|
||||||
(value) => {
|
(value) => {
|
||||||
updateValue(value)
|
updateValue(value, InputNumberEventType.Watch)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// 监听 max, min, precision 变化
|
// 监听 max, min, precision 变化
|
||||||
watch([() => props.max, () => props.min, () => props.precision], () => {
|
watch([() => props.max, () => props.min, () => props.precision], () => {
|
||||||
const value = formatValue(inputValue.value)
|
const value = formatValue(inputValue.value)
|
||||||
updateValue(value)
|
updateValue(value, InputNumberEventType.Watch)
|
||||||
})
|
})
|
||||||
|
|
||||||
// 判断两个值是否相等
|
/**
|
||||||
|
* 对比两个值是否相等
|
||||||
|
* @param value1 第一个值
|
||||||
|
* @param value2 第二个值
|
||||||
|
* @returns 是否相等
|
||||||
|
*/
|
||||||
function isValueEqual(value1: number | string, value2: number | string) {
|
function isValueEqual(value1: number | string, value2: number | string) {
|
||||||
return isEqual(String(value1), String(value2))
|
return isEqual(String(value1), String(value2))
|
||||||
}
|
}
|
||||||
@ -97,7 +106,11 @@ function toPrecision(value: number) {
|
|||||||
return Number(parseFloat(`${Math.round(value * Math.pow(10, precision)) / Math.pow(10, precision)}`).toFixed(precision))
|
return Number(parseFloat(`${Math.round(value * Math.pow(10, precision)) / Math.pow(10, precision)}`).toFixed(precision))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取值的精度
|
/**
|
||||||
|
* 获取数字的小数位数
|
||||||
|
* @param value 需要计算精度的数字
|
||||||
|
* @returns 小数位数
|
||||||
|
*/
|
||||||
function getPrecision(value?: number) {
|
function getPrecision(value?: number) {
|
||||||
if (!isDef(value)) return 0
|
if (!isDef(value)) return 0
|
||||||
const valueString = value.toString()
|
const valueString = value.toString()
|
||||||
@ -109,20 +122,19 @@ function getPrecision(value?: number) {
|
|||||||
return precision
|
return precision
|
||||||
}
|
}
|
||||||
|
|
||||||
// 严格按照步进值递增或递减
|
/**
|
||||||
|
* 按步进值严格递增或递减
|
||||||
|
* @param value 当前值
|
||||||
|
* @returns 按步进值调整后的值
|
||||||
|
*/
|
||||||
function toStrictlyStep(value: number | string) {
|
function toStrictlyStep(value: number | string) {
|
||||||
const stepPrecision = getPrecision(props.step)
|
const stepPrecision = getPrecision(props.step)
|
||||||
const precisionFactory = Math.pow(10, stepPrecision)
|
const precisionFactory = Math.pow(10, stepPrecision)
|
||||||
return (Math.round(Number(value) / props.step) * precisionFactory * props.step) / precisionFactory
|
return (Math.round(Number(value) / props.step) * precisionFactory * props.step) / precisionFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新值
|
// 内部更新处理函数
|
||||||
function updateValue(value: string | number, fromUser: boolean = false) {
|
function doUpdate(value: string | number) {
|
||||||
if (isValueEqual(value, inputValue.value)) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const update = () => {
|
|
||||||
inputValue.value = value
|
inputValue.value = value
|
||||||
const formatted = formatValue(value)
|
const formatted = formatValue(value)
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
@ -130,7 +142,55 @@ function updateValue(value: string | number, fromUser: boolean = false) {
|
|||||||
emit('update:modelValue', inputValue.value)
|
emit('update:modelValue', inputValue.value)
|
||||||
emit('change', { value: inputValue.value })
|
emit('change', { value: inputValue.value })
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清理输入字符串中多余的小数点
|
||||||
|
* @param value 输入的字符串
|
||||||
|
* @returns 清理后的字符串
|
||||||
|
*/
|
||||||
|
function cleanExtraDecimal(value: string): string {
|
||||||
|
const precisionAllowed = Number(props.precision) > 0
|
||||||
|
if (precisionAllowed) {
|
||||||
|
const dotIndex = value.indexOf('.')
|
||||||
|
if (dotIndex === -1) {
|
||||||
|
return value
|
||||||
|
} else {
|
||||||
|
const integerPart = value.substring(0, dotIndex + 1)
|
||||||
|
// 去除后续出现的'.'
|
||||||
|
const decimalPart = value.substring(dotIndex + 1).replace(/\./g, '')
|
||||||
|
return integerPart + decimalPart
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// 不允许小数:保留整数部分
|
||||||
|
const dotIndex = value.indexOf('.')
|
||||||
|
return dotIndex !== -1 ? value.substring(0, dotIndex) : value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新输入框的值
|
||||||
|
* @param value 新的值
|
||||||
|
* @param eventType 触发更新的事件类型
|
||||||
|
*/
|
||||||
|
function updateValue(value: string | number, eventType: InputNumberEventType = InputNumberEventType.Input) {
|
||||||
|
const fromUser = eventType !== InputNumberEventType.Watch // watch时不认为是用户直接输入
|
||||||
|
const forceFormat = eventType === InputNumberEventType.Blur || eventType === InputNumberEventType.Button
|
||||||
|
// 对于 Input 和 Watch 类型,如果值以'.'结尾,则直接更新,不进行格式化
|
||||||
|
if ((eventType === InputNumberEventType.Input || eventType === InputNumberEventType.Watch) && String(value).endsWith('.') && props.precision) {
|
||||||
|
inputValue.value = value
|
||||||
|
nextTick(() => {
|
||||||
|
inputValue.value = cleanExtraDecimal(String(value))
|
||||||
|
emit('update:modelValue', inputValue.value)
|
||||||
|
emit('change', { value: inputValue.value })
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!forceFormat && isValueEqual(value, inputValue.value)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const update = () => doUpdate(value)
|
||||||
|
|
||||||
if (fromUser) {
|
if (fromUser) {
|
||||||
callInterceptor(props.beforeChange, {
|
callInterceptor(props.beforeChange, {
|
||||||
@ -153,11 +213,10 @@ function changeStep(val: string | number, step: number) {
|
|||||||
return toPrecision((val * precisionFactor + step * precisionFactor) / precisionFactor)
|
return toPrecision((val * precisionFactor + step * precisionFactor) / precisionFactor)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 改变值
|
|
||||||
function changeValue(step: number) {
|
function changeValue(step: number) {
|
||||||
if ((step < 0 && (minDisabled.value || props.disableMinus)) || (step > 0 && (maxDisabled.value || props.disablePlus))) return
|
if ((step < 0 && (minDisabled.value || props.disableMinus)) || (step > 0 && (maxDisabled.value || props.disablePlus))) return
|
||||||
const value = changeStep(inputValue.value, step)
|
const value = changeStep(inputValue.value, step)
|
||||||
updateValue(value, true)
|
updateValue(value, InputNumberEventType.Button)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 减少值
|
// 减少值
|
||||||
@ -170,10 +229,15 @@ function add() {
|
|||||||
changeValue(props.step)
|
changeValue(props.step)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理输入事件
|
|
||||||
function handleInput(event: any) {
|
function handleInput(event: any) {
|
||||||
let value = event.detail.value || ''
|
const rawValue = event.detail.value || ''
|
||||||
updateValue(value, true)
|
updateValue(rawValue, InputNumberEventType.Input)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleBlur(event: any) {
|
||||||
|
const value = event.detail.value || ''
|
||||||
|
updateValue(value, InputNumberEventType.Blur)
|
||||||
|
emit('blur', { value })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理聚焦事件
|
// 处理聚焦事件
|
||||||
@ -181,15 +245,6 @@ function handleFocus(event: any) {
|
|||||||
emit('focus', event.detail)
|
emit('focus', event.detail)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理失焦事件
|
|
||||||
function handleBlur(event: any) {
|
|
||||||
const value = event.detail.value || ''
|
|
||||||
updateValue(value, true)
|
|
||||||
emit('blur', {
|
|
||||||
value
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 格式化值
|
// 格式化值
|
||||||
function formatValue(value: string | number) {
|
function formatValue(value: string | number) {
|
||||||
if (props.allowNull && (!isDef(value) || value === '')) {
|
if (props.allowNull && (!isDef(value) || value === '')) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user