123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283 |
- <template>
- <div
- @dragstart.prevent
- :class="[
- 'el-input-number',
- inputNumberSize ? 'el-input-number--' + inputNumberSize : '',
- { 'is-disabled': inputNumberDisabled },
- { 'is-without-controls': !controls },
- { 'is-controls-right': controlsAtRight }
- ]">
- <span
- class="el-input-number__decrease"
- role="button"
- v-if="controls"
- v-repeat-click="decrease"
- :class="{'is-disabled': minDisabled}"
- @keydown.enter="decrease">
- <i :class="`el-icon-${controlsAtRight ? 'arrow-down' : 'minus'}`"></i>
- </span>
- <span
- class="el-input-number__increase"
- role="button"
- v-if="controls"
- v-repeat-click="increase"
- :class="{'is-disabled': maxDisabled}"
- @keydown.enter="increase">
- <i :class="`el-icon-${controlsAtRight ? 'arrow-up' : 'plus'}`"></i>
- </span>
- <el-input
- ref="input"
- :value="displayValue"
- :placeholder="placeholder"
- :disabled="inputNumberDisabled"
- :size="inputNumberSize"
- :max="max"
- :min="min"
- :name="name"
- :label="label"
- @keydown.up.native.prevent="increase"
- @keydown.down.native.prevent="decrease"
- @blur="handleBlur"
- @focus="handleFocus"
- @input="handleInput"
- @change="handleInputChange">
- </el-input>
- </div>
- </template>
- <script>
- import ElInput from 'element-ui/packages/input';
- import Focus from 'element-ui/src/mixins/focus';
- import RepeatClick from 'element-ui/src/directives/repeat-click';
- export default {
- name: 'ElInputNumber',
- mixins: [Focus('input')],
- inject: {
- elForm: {
- default: ''
- },
- elFormItem: {
- default: ''
- }
- },
- directives: {
- repeatClick: RepeatClick
- },
- components: {
- ElInput
- },
- props: {
- step: {
- type: Number,
- default: 1
- },
- stepStrictly: {
- type: Boolean,
- default: false
- },
- max: {
- type: Number,
- default: Infinity
- },
- min: {
- type: Number,
- default: -Infinity
- },
- value: {},
- disabled: Boolean,
- size: String,
- controls: {
- type: Boolean,
- default: true
- },
- controlsPosition: {
- type: String,
- default: ''
- },
- name: String,
- label: String,
- placeholder: String,
- precision: {
- type: Number,
- validator(val) {
- return val >= 0 && val === parseInt(val, 10);
- }
- }
- },
- data() {
- return {
- currentValue: 0,
- userInput: null
- };
- },
- watch: {
- value: {
- immediate: true,
- handler(value) {
- let newVal = value === undefined ? value : Number(value);
- if (newVal !== undefined) {
- if (isNaN(newVal)) {
- return;
- }
- if (this.stepStrictly) {
- const stepPrecision = this.getPrecision(this.step);
- const precisionFactor = Math.pow(10, stepPrecision);
- newVal = Math.round(newVal / this.step) * precisionFactor * this.step / precisionFactor;
- }
- 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;
- this.userInput = null;
- this.$emit('input', newVal);
- }
- }
- },
- computed: {
- minDisabled() {
- return this._decrease(this.value, this.step) < this.min;
- },
- maxDisabled() {
- return this._increase(this.value, this.step) > this.max;
- },
- 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.controls && this.controlsPosition === 'right';
- },
- _elFormItemSize() {
- return (this.elFormItem || {}).elFormItemSize;
- },
- inputNumberSize() {
- return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;
- },
- inputNumberDisabled() {
- return this.disabled || !!(this.elForm || {}).disabled;
- },
- displayValue() {
- if (this.userInput !== null) {
- return this.userInput;
- }
- let currentValue = this.currentValue;
- if (typeof currentValue === 'number') {
- if (this.stepStrictly) {
- const stepPrecision = this.getPrecision(this.step);
- const precisionFactor = Math.pow(10, stepPrecision);
- currentValue = Math.round(currentValue / this.step) * precisionFactor * this.step / precisionFactor;
- }
- if (this.precision !== undefined) {
- currentValue = currentValue.toFixed(this.precision);
- }
- }
- return currentValue;
- }
- },
- methods: {
- toPrecision(num, precision) {
- if (precision === undefined) precision = this.numPrecision;
- return parseFloat(Math.round(num * Math.pow(10, precision)) / Math.pow(10, precision));
- },
- getPrecision(value) {
- if (value === undefined) return 0;
- const valueString = value.toString();
- const dotPosition = valueString.indexOf('.');
- let precision = 0;
- if (dotPosition !== -1) {
- precision = valueString.length - dotPosition - 1;
- }
- return precision;
- },
- _increase(val, step) {
- if (typeof val !== 'number' && val !== undefined) return this.currentValue;
- 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.numPrecision);
- return this.toPrecision((precisionFactor * val - precisionFactor * step) / precisionFactor);
- },
- increase() {
- if (this.inputNumberDisabled || this.maxDisabled) return;
- const value = this.value || 0;
- const newVal = this._increase(value, this.step);
- this.setCurrentValue(newVal);
- },
- decrease() {
- if (this.inputNumberDisabled || this.minDisabled) return;
- const value = this.value || 0;
- const newVal = this._decrease(value, this.step);
- this.setCurrentValue(newVal);
- },
- handleBlur(event) {
- this.$emit('blur', event);
- },
- 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) return;
- this.userInput = null;
- this.$emit('input', newVal);
- this.$emit('change', newVal, oldVal);
- this.currentValue = newVal;
- },
- handleInput(value) {
- this.userInput = value;
- },
- handleInputChange(value) {
- const newVal = value === '' ? undefined : Number(value);
- if (!isNaN(newVal) || value === '') {
- this.setCurrentValue(newVal);
- }
- this.userInput = null;
- },
- select() {
- this.$refs.input.select();
- }
- },
- mounted() {
- let innerInput = this.$refs.input.$refs.input;
- innerInput.setAttribute('role', 'spinbutton');
- innerInput.setAttribute('aria-valuemax', this.max);
- innerInput.setAttribute('aria-valuemin', this.min);
- innerInput.setAttribute('aria-valuenow', this.currentValue);
- innerInput.setAttribute('aria-disabled', this.inputNumberDisabled);
- },
- updated() {
- if (!this.$refs || !this.$refs.input) return;
- const innerInput = this.$refs.input.$refs.input;
- innerInput.setAttribute('aria-valuenow', this.currentValue);
- }
- };
- </script>
|