diff --git a/examples/docs/en-US/input-number.md b/examples/docs/en-US/input-number.md index 3d9a20c11..6e7081823 100644 --- a/examples/docs/en-US/input-number.md +++ b/examples/docs/en-US/input-number.md @@ -99,6 +99,31 @@ Allows you to define incremental steps. ``` ::: +### Precision + +:::demo Add `precision` attribute to set the precision of input value. + +```html + + +``` + +::: + +:::tip +The value of `precision` must be a positive integer and should not be less than the decimal places of `step`. +::: + ### Size Use attribute `size` to set additional sizes with `medium`, `small` or `mini`. @@ -159,6 +184,7 @@ Use attribute `size` to set additional sizes with `medium`, `small` or `mini`. |min | the minimum allowed value | number | — | `-Infinity` | |max | the maximum allowed value | number | — | `Infinity` | |step | incremental step | number | — | 1 | +|precision | precision of input value | number | — | — | |size | size of the component | string | large/small| — | |disabled| whether the component is disabled | boolean | — | false | |controls| whether to enable the control buttons | boolean | — | true | diff --git a/examples/docs/es/input-number.md b/examples/docs/es/input-number.md index 929fc4812..f0bdb6543 100644 --- a/examples/docs/es/input-number.md +++ b/examples/docs/es/input-number.md @@ -99,6 +99,31 @@ Le permite definir el nivel de incremento de los saltos. ``` ::: +### Precision + +:::demo Add `precision` attribute to set the precision of input value. + +```html + + +``` + +::: + +:::tip +The value of `precision` must be a positive integer and should not be less than the decimal places of `step`. +::: + ### Tamaño Utilice el atributo `size` para establecer tamaños adicionales con `medium`, `small` o `mini`. @@ -160,6 +185,7 @@ Utilice el atributo `size` para establecer tamaños adicionales con `medium`, `s | min | el valor mínimo permitido | number | — | `-Infinity` | | max | el valor maximo permitido | number | — | `Infinity` | | step | incremento (salto) | number | — | 1 | +| precision | precision of input value | number | — | — | | size | tamaño del componente | string | large/small | — | | disabled | si el componente esta deshabilitado | boolean | — | false | | controls | si se activan los botones de control | boolean | — | true | diff --git a/examples/docs/zh-CN/input-number.md b/examples/docs/zh-CN/input-number.md index 4cf1d5ca2..10c9ef1d3 100644 --- a/examples/docs/zh-CN/input-number.md +++ b/examples/docs/zh-CN/input-number.md @@ -9,7 +9,8 @@ num5: 1, num6: 1, num7: 1, - num8: 1 + num8: 1, + num9: 1 } }, methods: { @@ -97,6 +98,31 @@ ``` ::: +### 精度 + +:::demo 设置 `precision` 属性可以控制数值精度,接收一个 `Number`。 + +```html + + +``` + +::: + +:::tip +`precision` 的值必须是一个正整数,并且不能小于 `step` 的小数位数。 +::: + ### 尺寸 额外提供了 `medium`、`small`、`mini` 三种尺寸的数字输入框 @@ -156,6 +182,7 @@ | min | 设置计数器允许的最小值 | number | — | -Infinity | | max | 设置计数器允许的最大值 | number | — | Infinity | | step | 计数器步长 | number | — | 1 | +| precision| 数值精度 | number | — | — | | size | 计数器尺寸 | string | large, small | — | | disabled | 是否禁用计数器 | boolean | — | false | | controls | 是否使用控制按钮 | boolean | — | true | diff --git a/packages/input-number/src/input-number.vue b/packages/input-number/src/input-number.vue index 8f2a9873d..1dd52de3a 100644 --- a/packages/input-number/src/input-number.vue +++ b/packages/input-number/src/input-number.vue @@ -28,7 +28,7 @@ = 0 && val === parseInt(val, 10); + } + } }, data() { return { @@ -108,7 +114,14 @@ immediate: true, handler(value) { let newVal = value === undefined ? value : Number(value); - if (newVal !== undefined && isNaN(newVal)) return; + if (newVal !== undefined) { + if (isNaN(newVal)) { + return; + } + if (this.precision !== undefined) { + newVal = this.toPrecision(newVal, this.precision); + } + } if (newVal >= this.max) newVal = this.max; if (newVal <= this.min) newVal = this.min; this.currentValue = newVal; @@ -123,9 +136,17 @@ maxDisabled() { return this._increase(this.value, this.step) > this.max; }, - precision() { - const { value, step, getPrecision } = this; - return Math.max(getPrecision(value), getPrecision(step)); + numPrecision() { + const { value, step, getPrecision, precision } = this; + const stepPrecision = getPrecision(step); + if (precision !== undefined) { + if (stepPrecision > precision) { + console.warn('[Element Warn][InputNumber]precision should not be less than the decimal places of step'); + } + return precision; + } else { + return Math.max(getPrecision(value), stepPrecision); + } }, controlsAtRight() { return this.controlsPosition === 'right'; @@ -138,11 +159,19 @@ }, inputNumberDisabled() { return this.disabled || (this.elForm || {}).disabled; + }, + currentInputValue() { + const currentValue = this.currentValue; + if (typeof currentValue === 'number' && this.precision !== undefined) { + return currentValue.toFixed(this.precision); + } else { + return currentValue; + } } }, methods: { toPrecision(num, precision) { - if (precision === undefined) precision = this.precision; + if (precision === undefined) precision = this.numPrecision; return parseFloat(parseFloat(Number(num).toFixed(precision))); }, getPrecision(value) { @@ -158,14 +187,14 @@ _increase(val, step) { if (typeof val !== 'number' && val !== undefined) return this.currentValue; - const precisionFactor = Math.pow(10, this.precision); + const precisionFactor = Math.pow(10, this.numPrecision); // Solve the accuracy problem of JS decimal calculation by converting the value to integer. return this.toPrecision((precisionFactor * val + precisionFactor * step) / precisionFactor); }, _decrease(val, step) { if (typeof val !== 'number' && val !== undefined) return this.currentValue; - const precisionFactor = Math.pow(10, this.precision); + const precisionFactor = Math.pow(10, this.numPrecision); return this.toPrecision((precisionFactor * val - precisionFactor * step) / precisionFactor); }, @@ -183,17 +212,20 @@ }, handleBlur(event) { this.$emit('blur', event); - this.$refs.input.setCurrentValue(this.currentValue); + this.$refs.input.setCurrentValue(this.currentInputValue); }, handleFocus(event) { this.$emit('focus', event); }, setCurrentValue(newVal) { const oldVal = this.currentValue; + if (typeof newVal === 'number' && this.precision !== undefined) { + newVal = this.toPrecision(newVal, this.precision); + } if (newVal >= this.max) newVal = this.max; if (newVal <= this.min) newVal = this.min; if (oldVal === newVal) { - this.$refs.input.setCurrentValue(this.currentValue); + this.$refs.input.setCurrentValue(this.currentInputValue); return; } this.$emit('input', newVal); diff --git a/test/unit/specs/input-number.spec.js b/test/unit/specs/input-number.spec.js index deef42b73..4ba16be1e 100644 --- a/test/unit/specs/input-number.spec.js +++ b/test/unit/specs/input-number.spec.js @@ -220,6 +220,51 @@ describe('InputNumber', () => { done(); }); }); + describe('precision', () => { + it('precision is 2', () => { + vm = createVue({ + template: ` + + + `, + data() { + return { + value: 6.999 + }; + } + }, true); + expect(vm.value === 7); + expect(vm.$el.querySelector('input').value).to.be.equal('7.00'); + }); + + it('precision greater than the precision of step', done => { + vm = createVue({ + template: ` + + + `, + data() { + return { + value: 6.999 + }; + } + }, true); + const input = vm.$el.querySelector('input'); + const btnIncrease = vm.$el.querySelector('.el-input-number__increase'); + + expect(vm.value === 7); + expect(input.value).to.be.equal('7'); + + triggerEvent(btnIncrease, 'mousedown'); + triggerClick(document, 'mouseup'); + + vm.$nextTick(_ => { + expect(vm.value).to.be.equal(7); + expect(input.value).to.be.equal('7'); + done(); + }); + }); + }); it('controls', () => { vm = createVue({ template: ` diff --git a/types/input-number.d.ts b/types/input-number.d.ts index 53fbd3727..deec6f59b 100644 --- a/types/input-number.d.ts +++ b/types/input-number.d.ts @@ -34,6 +34,9 @@ export declare class ElInputNumber extends ElementUIComponent { /** Same as name in native input */ name: string + /** Precision of input value */ + precision: Number + /** * Focus the Input component */