InputNumber: add precision attribute (#11281)

pull/11320/head
hetech 2018-05-23 14:10:34 +08:00 committed by 杨奕
parent 66f90b9e37
commit bcfb1d3c71
6 changed files with 171 additions and 12 deletions

View File

@ -99,6 +99,31 @@ Allows you to define incremental steps.
``` ```
::: :::
### Precision
:::demo Add `precision` attribute to set the precision of input value.
```html
<template>
<el-input-number v-model="num9" :precision="2" :step="0.1" :max="10"></el-input-number>
</template>
<script>
export default {
data() {
return {
num9: 1
}
}
};
</script>
```
:::
:::tip
The value of `precision` must be a positive integer and should not be less than the decimal places of `step`.
:::
### Size ### Size
Use attribute `size` to set additional sizes with `medium`, `small` or `mini`. 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` | |min | the minimum allowed value | number | — | `-Infinity` |
|max | the maximum allowed value | number | — | `Infinity` | |max | the maximum allowed value | number | — | `Infinity` |
|step | incremental step | number | — | 1 | |step | incremental step | number | — | 1 |
|precision | precision of input value | number | — | — |
|size | size of the component | string | large/small| — | |size | size of the component | string | large/small| — |
|disabled| whether the component is disabled | boolean | — | false | |disabled| whether the component is disabled | boolean | — | false |
|controls| whether to enable the control buttons | boolean | — | true | |controls| whether to enable the control buttons | boolean | — | true |

View File

@ -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
<template>
<el-input-number v-model="num9" :precision="2" :step="0.1" :max="10"></el-input-number>
</template>
<script>
export default {
data() {
return {
num9: 1
}
}
};
</script>
```
:::
:::tip
The value of `precision` must be a positive integer and should not be less than the decimal places of `step`.
:::
### Tamaño ### Tamaño
Utilice el atributo `size` para establecer tamaños adicionales con `medium`, `small` o `mini`. 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` | | min | el valor mínimo permitido | number | — | `-Infinity` |
| max | el valor maximo permitido | number | — | `Infinity` | | max | el valor maximo permitido | number | — | `Infinity` |
| step | incremento (salto) | number | — | 1 | | step | incremento (salto) | number | — | 1 |
| precision | precision of input value | number | — | — |
| size | tamaño del componente | string | large/small | — | | size | tamaño del componente | string | large/small | — |
| disabled | si el componente esta deshabilitado | boolean | — | false | | disabled | si el componente esta deshabilitado | boolean | — | false |
| controls | si se activan los botones de control | boolean | — | true | | controls | si se activan los botones de control | boolean | — | true |

View File

@ -9,7 +9,8 @@
num5: 1, num5: 1,
num6: 1, num6: 1,
num7: 1, num7: 1,
num8: 1 num8: 1,
num9: 1
} }
}, },
methods: { methods: {
@ -97,6 +98,31 @@
``` ```
::: :::
### 精度
:::demo 设置 `precision` 属性可以控制数值精度,接收一个 `Number`
```html
<template>
<el-input-number v-model="num9" :precision="2" :step="0.1" :max="10"></el-input-number>
</template>
<script>
export default {
data() {
return {
num9: 1
}
}
};
</script>
```
:::
:::tip
`precision` 的值必须是一个正整数,并且不能小于 `step` 的小数位数。
:::
### 尺寸 ### 尺寸
额外提供了 `medium`、`small`、`mini` 三种尺寸的数字输入框 额外提供了 `medium`、`small`、`mini` 三种尺寸的数字输入框
@ -156,6 +182,7 @@
| min | 设置计数器允许的最小值 | number | — | -Infinity | | min | 设置计数器允许的最小值 | number | — | -Infinity |
| max | 设置计数器允许的最大值 | number | — | Infinity | | max | 设置计数器允许的最大值 | number | — | Infinity |
| step | 计数器步长 | number | — | 1 | | step | 计数器步长 | number | — | 1 |
| precision| 数值精度 | number | — | — |
| size | 计数器尺寸 | string | large, small | — | | size | 计数器尺寸 | string | large, small | — |
| disabled | 是否禁用计数器 | boolean | — | false | | disabled | 是否禁用计数器 | boolean | — | false |
| controls | 是否使用控制按钮 | boolean | — | true | | controls | 是否使用控制按钮 | boolean | — | true |

View File

@ -28,7 +28,7 @@
</span> </span>
<el-input <el-input
ref="input" ref="input"
:value="currentValue" :value="currentInputValue"
:disabled="inputNumberDisabled" :disabled="inputNumberDisabled"
:size="inputNumberSize" :size="inputNumberSize"
:max="max" :max="max"
@ -96,7 +96,13 @@
default: '' default: ''
}, },
name: String, name: String,
label: String label: String,
precision: {
type: Number,
validator(val) {
return val >= 0 && val === parseInt(val, 10);
}
}
}, },
data() { data() {
return { return {
@ -108,7 +114,14 @@
immediate: true, immediate: true,
handler(value) { handler(value) {
let newVal = value === undefined ? value : Number(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.max) newVal = this.max;
if (newVal <= this.min) newVal = this.min; if (newVal <= this.min) newVal = this.min;
this.currentValue = newVal; this.currentValue = newVal;
@ -123,9 +136,17 @@
maxDisabled() { maxDisabled() {
return this._increase(this.value, this.step) > this.max; return this._increase(this.value, this.step) > this.max;
}, },
precision() { numPrecision() {
const { value, step, getPrecision } = this; const { value, step, getPrecision, precision } = this;
return Math.max(getPrecision(value), getPrecision(step)); 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() { controlsAtRight() {
return this.controlsPosition === 'right'; return this.controlsPosition === 'right';
@ -138,11 +159,19 @@
}, },
inputNumberDisabled() { inputNumberDisabled() {
return this.disabled || (this.elForm || {}).disabled; 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: { methods: {
toPrecision(num, precision) { toPrecision(num, precision) {
if (precision === undefined) precision = this.precision; if (precision === undefined) precision = this.numPrecision;
return parseFloat(parseFloat(Number(num).toFixed(precision))); return parseFloat(parseFloat(Number(num).toFixed(precision)));
}, },
getPrecision(value) { getPrecision(value) {
@ -158,14 +187,14 @@
_increase(val, step) { _increase(val, step) {
if (typeof val !== 'number' && val !== undefined) return this.currentValue; 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. // Solve the accuracy problem of JS decimal calculation by converting the value to integer.
return this.toPrecision((precisionFactor * val + precisionFactor * step) / precisionFactor); return this.toPrecision((precisionFactor * val + precisionFactor * step) / precisionFactor);
}, },
_decrease(val, step) { _decrease(val, step) {
if (typeof val !== 'number' && val !== undefined) return this.currentValue; 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); return this.toPrecision((precisionFactor * val - precisionFactor * step) / precisionFactor);
}, },
@ -183,17 +212,20 @@
}, },
handleBlur(event) { handleBlur(event) {
this.$emit('blur', event); this.$emit('blur', event);
this.$refs.input.setCurrentValue(this.currentValue); this.$refs.input.setCurrentValue(this.currentInputValue);
}, },
handleFocus(event) { handleFocus(event) {
this.$emit('focus', event); this.$emit('focus', event);
}, },
setCurrentValue(newVal) { setCurrentValue(newVal) {
const oldVal = this.currentValue; 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.max) newVal = this.max;
if (newVal <= this.min) newVal = this.min; if (newVal <= this.min) newVal = this.min;
if (oldVal === newVal) { if (oldVal === newVal) {
this.$refs.input.setCurrentValue(this.currentValue); this.$refs.input.setCurrentValue(this.currentInputValue);
return; return;
} }
this.$emit('input', newVal); this.$emit('input', newVal);

View File

@ -220,6 +220,51 @@ describe('InputNumber', () => {
done(); done();
}); });
}); });
describe('precision', () => {
it('precision is 2', () => {
vm = createVue({
template: `
<el-input-number v-model="value" :max="8" :precision="2">
</el-input-number>
`,
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: `
<el-input-number v-model="value" :max="8" :precision="0" :step="0.1">
</el-input-number>
`,
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', () => { it('controls', () => {
vm = createVue({ vm = createVue({
template: ` template: `

View File

@ -34,6 +34,9 @@ export declare class ElInputNumber extends ElementUIComponent {
/** Same as name in native input */ /** Same as name in native input */
name: string name: string
/** Precision of input value */
precision: Number
/** /**
* Focus the Input component * Focus the Input component
*/ */