Skip to content

Commit e3a03b1

Browse files
fix: 🐛 修复 InputNumber 微信小程序设置了precision后无法输入小数点的问题 (#902)
Closes: #878
1 parent 604faeb commit e3a03b1

3 files changed

Lines changed: 106 additions & 32 deletions

File tree

src/pages/inputNumber/Index.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
</view>
2323
</demo-block>
2424
<demo-block title="设置小数精度">
25-
<wd-input-number v-model="value6" @change="handleChange6" :precision="2" :step="0.1" />
25+
<wd-input-number v-model="value6" @change="handleChange6" :precision="1" :step="0.1" />
2626
</demo-block>
2727
<demo-block title="输入严格为步数的倍数">
2828
<wd-input-number v-model="value7" @change="handleChange7" step-strictly :step="2" />
@@ -49,7 +49,7 @@ const value2 = ref<number>(1)
4949
const value3 = ref<number>(1)
5050
const value4 = ref<number>(2)
5151
const value5 = ref<number>(1)
52-
const value6 = ref<string>('1.205')
52+
const value6 = ref<string>('1.2')
5353
const value7 = ref<number>(1)
5454
const value8 = ref<number>(2)
5555
const value9 = ref<string>('')

src/uni_modules/wot-design-uni/components/wd-input-number/types.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* @Author: weisheng
33
* @Date: 2024-03-15 20:40:34
4-
* @LastEditTime: 2025-02-11 18:38:54
4+
* @LastEditTime: 2025-02-19 12:47:54
55
* @LastEditors: weisheng
66
* @Description:
77
* @FilePath: /wot-design-uni/src/uni_modules/wot-design-uni/components/wd-input-number/types.ts
@@ -10,8 +10,27 @@
1010
import type { PropType } from 'vue'
1111
import { baseProps, makeBooleanProp, makeNumberProp, makeNumericProp, makeRequiredProp, makeStringProp, numericProp } from '../common/props'
1212

13+
/**
14+
* 输入框值变化前的回调函数类型定义
15+
* @param value 输入框的新值
16+
* @returns 返回布尔值或Promise<boolean>,用于控制是否允许值的变化
17+
*/
1318
export type InputNumberBeforeChange = (value: number | string) => boolean | Promise<boolean>
1419

20+
/**
21+
* 输入数字组件事件类型枚举
22+
* Input: 用户输入事件
23+
* Blur: 失焦事件
24+
* Watch: 监听值变化事件
25+
* Button: 按钮点击事件
26+
*/
27+
export enum InputNumberEventType {
28+
Input = 'input',
29+
Blur = 'blur',
30+
Watch = 'watch',
31+
Button = 'button'
32+
}
33+
1534
export const inputNumberProps = {
1635
...baseProps,
1736
/**

src/uni_modules/wot-design-uni/components/wd-input-number/wd-input-number.vue

Lines changed: 84 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -42,21 +42,25 @@ export default {
4242
import wdIcon from '../wd-icon/wd-icon.vue'
4343
import { computed, nextTick, ref, watch } from 'vue'
4444
import { isDef, isEqual } from '../common/util'
45-
import { inputNumberProps } from './types'
45+
import { inputNumberProps, InputNumberEventType } from './types'
4646
import { callInterceptor } from '../common/interceptor'
4747
4848
const props = defineProps(inputNumberProps)
4949
const emit = defineEmits(['focus', 'blur', 'change', 'update:modelValue'])
5050
const inputValue = ref<string | number>(getInitValue()) // 输入框的值
5151
52-
// 减号是否禁用
52+
/**
53+
* 判断数字是否达到最小值限制
54+
*/
5355
const minDisabled = computed(() => {
5456
const value = formatValue(inputValue.value)
5557
const { disabled, min, step } = props
5658
return disabled || Number(value) <= min || changeStep(value, -step) < min
5759
})
5860
59-
// 加号是否禁用
61+
/**
62+
* 判断数字是否达到最大值限制
63+
*/
6064
const maxDisabled = computed(() => {
6165
const value = formatValue(inputValue.value)
6266
const { disabled, max, step } = props
@@ -67,17 +71,22 @@ const maxDisabled = computed(() => {
6771
watch(
6872
() => props.modelValue,
6973
(value) => {
70-
updateValue(value)
74+
updateValue(value, InputNumberEventType.Watch)
7175
}
7276
)
7377
7478
// 监听 max, min, precision 变化
7579
watch([() => props.max, () => props.min, () => props.precision], () => {
7680
const value = formatValue(inputValue.value)
77-
updateValue(value)
81+
updateValue(value, InputNumberEventType.Watch)
7882
})
7983
80-
// 判断两个值是否相等
84+
/**
85+
* 对比两个值是否相等
86+
* @param value1 第一个值
87+
* @param value2 第二个值
88+
* @returns 是否相等
89+
*/
8190
function isValueEqual(value1: number | string, value2: number | string) {
8291
return isEqual(String(value1), String(value2))
8392
}
@@ -97,7 +106,11 @@ function toPrecision(value: number) {
97106
return Number(parseFloat(`${Math.round(value * Math.pow(10, precision)) / Math.pow(10, precision)}`).toFixed(precision))
98107
}
99108
100-
// 获取值的精度
109+
/**
110+
* 获取数字的小数位数
111+
* @param value 需要计算精度的数字
112+
* @returns 小数位数
113+
*/
101114
function getPrecision(value?: number) {
102115
if (!isDef(value)) return 0
103116
const valueString = value.toString()
@@ -109,28 +122,75 @@ function getPrecision(value?: number) {
109122
return precision
110123
}
111124
112-
// 严格按照步进值递增或递减
125+
/**
126+
* 按步进值严格递增或递减
127+
* @param value 当前值
128+
* @returns 按步进值调整后的值
129+
*/
113130
function toStrictlyStep(value: number | string) {
114131
const stepPrecision = getPrecision(props.step)
115132
const precisionFactory = Math.pow(10, stepPrecision)
116133
return (Math.round(Number(value) / props.step) * precisionFactory * props.step) / precisionFactory
117134
}
118135
119-
// 更新值
120-
function updateValue(value: string | number, fromUser: boolean = false) {
121-
if (isValueEqual(value, inputValue.value)) {
122-
return
136+
// 内部更新处理函数
137+
function doUpdate(value: string | number) {
138+
inputValue.value = value
139+
const formatted = formatValue(value)
140+
nextTick(() => {
141+
inputValue.value = formatted
142+
emit('update:modelValue', inputValue.value)
143+
emit('change', { value: inputValue.value })
144+
})
145+
}
146+
147+
/**
148+
* 清理输入字符串中多余的小数点
149+
* @param value 输入的字符串
150+
* @returns 清理后的字符串
151+
*/
152+
function cleanExtraDecimal(value: string): string {
153+
const precisionAllowed = Number(props.precision) > 0
154+
if (precisionAllowed) {
155+
const dotIndex = value.indexOf('.')
156+
if (dotIndex === -1) {
157+
return value
158+
} else {
159+
const integerPart = value.substring(0, dotIndex + 1)
160+
// 去除后续出现的'.'
161+
const decimalPart = value.substring(dotIndex + 1).replace(/\./g, '')
162+
return integerPart + decimalPart
163+
}
164+
} else {
165+
// 不允许小数:保留整数部分
166+
const dotIndex = value.indexOf('.')
167+
return dotIndex !== -1 ? value.substring(0, dotIndex) : value
123168
}
169+
}
124170
125-
const update = () => {
171+
/**
172+
* 更新输入框的值
173+
* @param value 新的值
174+
* @param eventType 触发更新的事件类型
175+
*/
176+
function updateValue(value: string | number, eventType: InputNumberEventType = InputNumberEventType.Input) {
177+
const fromUser = eventType !== InputNumberEventType.Watch // watch时不认为是用户直接输入
178+
const forceFormat = eventType === InputNumberEventType.Blur || eventType === InputNumberEventType.Button
179+
// 对于 Input 和 Watch 类型,如果值以'.'结尾,则直接更新,不进行格式化
180+
if ((eventType === InputNumberEventType.Input || eventType === InputNumberEventType.Watch) && String(value).endsWith('.') && props.precision) {
126181
inputValue.value = value
127-
const formatted = formatValue(value)
128182
nextTick(() => {
129-
inputValue.value = formatted
183+
inputValue.value = cleanExtraDecimal(String(value))
130184
emit('update:modelValue', inputValue.value)
131185
emit('change', { value: inputValue.value })
132186
})
187+
return
133188
}
189+
if (!forceFormat && isValueEqual(value, inputValue.value)) {
190+
return
191+
}
192+
193+
const update = () => doUpdate(value)
134194
135195
if (fromUser) {
136196
callInterceptor(props.beforeChange, {
@@ -153,11 +213,10 @@ function changeStep(val: string | number, step: number) {
153213
return toPrecision((val * precisionFactor + step * precisionFactor) / precisionFactor)
154214
}
155215
156-
// 改变值
157216
function changeValue(step: number) {
158217
if ((step < 0 && (minDisabled.value || props.disableMinus)) || (step > 0 && (maxDisabled.value || props.disablePlus))) return
159218
const value = changeStep(inputValue.value, step)
160-
updateValue(value, true)
219+
updateValue(value, InputNumberEventType.Button)
161220
}
162221
163222
// 减少值
@@ -170,26 +229,22 @@ function add() {
170229
changeValue(props.step)
171230
}
172231
173-
// 处理输入事件
174232
function handleInput(event: any) {
175-
let value = event.detail.value || ''
176-
updateValue(value, true)
233+
const rawValue = event.detail.value || ''
234+
updateValue(rawValue, InputNumberEventType.Input)
235+
}
236+
237+
function handleBlur(event: any) {
238+
const value = event.detail.value || ''
239+
updateValue(value, InputNumberEventType.Blur)
240+
emit('blur', { value })
177241
}
178242
179243
// 处理聚焦事件
180244
function handleFocus(event: any) {
181245
emit('focus', event.detail)
182246
}
183247
184-
// 处理失焦事件
185-
function handleBlur(event: any) {
186-
const value = event.detail.value || ''
187-
updateValue(value, true)
188-
emit('blur', {
189-
value
190-
})
191-
}
192-
193248
// 格式化值
194249
function formatValue(value: string | number) {
195250
if (props.allowNull && (!isDef(value) || value === '')) {

0 commit comments

Comments
 (0)