<template> <div :class="wrapClasses"> <div :class="handlerClasses"> <a @click="up" @mouse.down="preventDefault" :class="upClasses"> <span :class="innerUpClasses" @click="preventDefault"></span> </a> <a @click="down" @mouse.down="preventDefault" :class="downClasses"> <span :class="innerDownClasses" @click="preventDefault"></span> </a> </div> <div :class="inputWrapClasses"> <input :class="inputClasses" :disabled="disabled" autocomplete="off" @focus="focus" @blur="blur" @keydown.stop="keyDown" @change="change" :value="value"> </div> </div> </template> <script> import { oneOf } from '../../utils/assist'; const prefixCls = 'ivu-input-number'; const iconPrefixCls = 'ivu-icon'; function isValueNumber (value) { return (/(^-?[0-9]+\.{1}\d+$)|(^-?[1-9][0-9]*$)/).test(value + ''); } function addNum (num1, num2) { let sq1, sq2, m; try { sq1 = num1.toString().split('.')[1].length; } catch (e) { sq1 = 0; } try { sq2 = num2.toString().split('.')[1].length; } catch (e) { sq2 = 0; } // if (sq1 === 0 || sq2 === 0) { // return num1 + num2; // } else { // m = Math.pow(10, Math.max(sq1, sq2)); // return (num1 * m + num2 * m) / m; // } m = Math.pow(10, Math.max(sq1, sq2)); return (num1 * m + num2 * m) / m; } export default { props: { max: { type: Number, default: Infinity }, min: { type: Number, default: -Infinity }, step: { type: Number, default: 1 }, value: { type: Number, default: 1 }, size: { validator (value) { return oneOf(value, ['small', 'large']); } }, disabled: { type: Boolean, default: false } }, data () { return { focused: false, upDisabled: false, downDisabled: false }; }, computed: { wrapClasses () { return [ `${prefixCls}`, { [`${prefixCls}-${this.size}`]: !!this.size, [`${prefixCls}-disabled`]: this.disabled, [`${prefixCls}-focused`]: this.focused } ]; }, handlerClasses () { return `${prefixCls}-handler-wrap`; }, upClasses () { return [ `${prefixCls}-handler`, `${prefixCls}-handler-up`, { [`${prefixCls}-handler-up-disabled`]: this.upDisabled } ]; }, innerUpClasses () { return `${prefixCls}-handler-up-inner ${iconPrefixCls} ${iconPrefixCls}-ios-arrow-up`; }, downClasses () { return [ `${prefixCls}-handler`, `${prefixCls}-handler-down`, { [`${prefixCls}-handler-down-disabled`]: this.downDisabled } ]; }, innerDownClasses () { return `${prefixCls}-handler-down-inner ${iconPrefixCls} ${iconPrefixCls}-ios-arrow-down`; }, inputWrapClasses () { return `${prefixCls}-input-wrap`; }, inputClasses () { return `${prefixCls}-input`; } }, methods: { preventDefault (e) { e.preventDefault(); }, up () { if (this.upDisabled) { return false; } this.changeStep('up'); }, down () { if (this.downDisabled) { return false; } this.changeStep('down'); }, changeStep (type) { if (this.disabled) { return false; } let val = Number(this.value); const step = Number(this.step); if (isNaN(val)) { return false; } if (type == 'up') { val = addNum(val, step); } else if (type == 'down') { val = addNum(val, -step); } this.setValue(val); }, setValue (val) { this.$nextTick(() => { this.value = val; }); this.$emit('on-change', val); }, focus () { this.focused = true; }, blur () { this.focused = false; }, keyDown (e) { if (e.keyCode === 38) { e.preventDefault(); this.up(); } else if (e.keyCode === 40) { e.preventDefault(); this.down(); } }, change (event) { let val = event.target.value.trim(); const max = this.max; const min = this.min; if (isValueNumber(val)) { val = Number(val); this.value = val; if (val > max) { this.setValue(max); } else if (val < min) { this.setValue(min); } else { this.setValue(val); } } else { event.target.value = this.value; } }, changeVal (val) { if (isValueNumber(val) || val === 0) { val = Number(val); const step = this.step; this.upDisabled = val + step > this.max; this.downDisabled = val - step < this.min; } else { this.upDisabled = true; this.downDisabled = true; } } }, ready () { this.changeVal(this.value); }, watch: { value (val) { this.changeVal(val); } } }; </script>