input-number.vue 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. <template>
  2. <div class="el-input-number"
  3. :class="[
  4. size ? 'el-input-number--' + size : '',
  5. { 'is-disabled': disabled },
  6. { 'is-without-controls': !controls}
  7. ]"
  8. >
  9. <el-input
  10. :value="currentValue"
  11. @keydown.up.native="increase"
  12. @keydown.down.native="decrease"
  13. @blur="handleBlur"
  14. @input="handleInput"
  15. :disabled="disabled"
  16. :size="size"
  17. :class="{
  18. 'is-active': inputActive
  19. }">
  20. <template slot="prepend" v-if="$slots.prepend">
  21. <slot name="prepend"></slot>
  22. </template>
  23. <template slot="append" v-if="$slots.append">
  24. <slot name="append"></slot>
  25. </template>
  26. </el-input>
  27. <span
  28. v-if="controls"
  29. class="el-input-number__decrease el-icon-minus"
  30. :class="{'is-disabled': minDisabled}"
  31. v-repeat-click="decrease"
  32. @mouseenter="activeInput(minDisabled)"
  33. @mouseleave="inactiveInput(minDisabled)"
  34. >
  35. </span>
  36. <span
  37. v-if="controls"
  38. class="el-input-number__increase el-icon-plus"
  39. :class="{'is-disabled': maxDisabled}"
  40. v-repeat-click="increase"
  41. @mouseenter="activeInput(maxDisabled)"
  42. @mouseleave="inactiveInput(maxDisabled)"
  43. >
  44. </span>
  45. </div>
  46. </template>
  47. <script>
  48. import ElInput from 'element-ui/packages/input';
  49. import { once, on } from 'wind-dom/src/event';
  50. export default {
  51. name: 'ElInputNumber',
  52. props: {
  53. step: {
  54. type: Number,
  55. default: 1
  56. },
  57. max: {
  58. type: Number,
  59. default: Infinity
  60. },
  61. min: {
  62. type: Number,
  63. default: 0
  64. },
  65. value: {
  66. default: 0
  67. },
  68. disabled: Boolean,
  69. size: String,
  70. controls: {
  71. type: Boolean,
  72. default: true
  73. }
  74. },
  75. directives: {
  76. repeatClick: {
  77. bind(el, binding, vnode) {
  78. let interval = null;
  79. let startTime;
  80. const handler = () => {
  81. vnode.context[binding.expression]();
  82. };
  83. const clear = function() {
  84. if (new Date() - startTime < 100) {
  85. handler();
  86. }
  87. clearInterval(interval);
  88. interval = null;
  89. };
  90. on(el, 'mousedown', function() {
  91. startTime = new Date();
  92. once(document, 'mouseup', clear);
  93. interval = setInterval(function() {
  94. handler();
  95. }, 100);
  96. });
  97. }
  98. }
  99. },
  100. components: {
  101. ElInput
  102. },
  103. data() {
  104. // correct the init value
  105. let value = this.value;
  106. if (value < this.min) {
  107. this.$emit('input', this.min);
  108. value = this.min;
  109. }
  110. if (value > this.max) {
  111. this.$emit('input', this.max);
  112. value = this.max;
  113. }
  114. return {
  115. currentValue: value,
  116. inputActive: false
  117. };
  118. },
  119. watch: {
  120. value(val) {
  121. this.currentValue = val;
  122. },
  123. currentValue(newVal, oldVal) {
  124. let value = Number(newVal);
  125. if (value <= this.max && value >= this.min) {
  126. this.$emit('change', value, oldVal);
  127. this.$emit('input', value);
  128. }
  129. }
  130. },
  131. computed: {
  132. minDisabled() {
  133. return this.value - this.step < this.min;
  134. },
  135. maxDisabled() {
  136. return this.value + this.step > this.max;
  137. }
  138. },
  139. methods: {
  140. accSub(arg1, arg2) {
  141. var r1, r2, m, n;
  142. try {
  143. r1 = arg1.toString().split('.')[1].length;
  144. } catch (e) {
  145. r1 = 0;
  146. }
  147. try {
  148. r2 = arg2.toString().split('.')[1].length;
  149. } catch (e) {
  150. r2 = 0;
  151. }
  152. m = Math.pow(10, Math.max(r1, r2));
  153. n = (r1 >= r2) ? r1 : r2;
  154. return parseFloat(((arg1 * m - arg2 * m) / m).toFixed(n));
  155. },
  156. accAdd(arg1, arg2) {
  157. var r1, r2, m, c;
  158. try {
  159. r1 = arg1.toString().split('.')[1].length;
  160. } catch (e) {
  161. r1 = 0;
  162. }
  163. try {
  164. r2 = arg2.toString().split('.')[1].length;
  165. } catch (e) {
  166. r2 = 0;
  167. }
  168. c = Math.abs(r1 - r2);
  169. m = Math.pow(10, Math.max(r1, r2));
  170. if (c > 0) {
  171. var cm = Math.pow(10, c);
  172. if (r1 > r2) {
  173. arg1 = Number(arg1.toString().replace('.', ''));
  174. arg2 = Number(arg2.toString().replace('.', '')) * cm;
  175. } else {
  176. arg1 = Number(arg1.toString().replace('.', '')) * cm;
  177. arg2 = Number(arg2.toString().replace('.', ''));
  178. }
  179. } else {
  180. arg1 = Number(arg1.toString().replace('.', ''));
  181. arg2 = Number(arg2.toString().replace('.', ''));
  182. }
  183. return (arg1 + arg2) / m;
  184. },
  185. increase() {
  186. const value = this.value || 0;
  187. if (value + this.step > this.max || this.disabled) return;
  188. this.currentValue = this.accAdd(this.step, value);
  189. if (this.maxDisabled) {
  190. this.inputActive = false;
  191. }
  192. },
  193. decrease() {
  194. const value = this.value || 0;
  195. if (value - this.step < this.min || this.disabled) return;
  196. this.currentValue = this.accSub(value, this.step);
  197. if (this.minDisabled) {
  198. this.inputActive = false;
  199. }
  200. },
  201. activeInput(disabled) {
  202. if (!this.disabled && !disabled) {
  203. this.inputActive = true;
  204. }
  205. },
  206. inactiveInput(disabled) {
  207. if (!this.disabled && !disabled) {
  208. this.inputActive = false;
  209. }
  210. },
  211. handleBlur(event) {
  212. let value = Number(this.currentValue);
  213. if (isNaN(value) || value > this.max || value < this.min) {
  214. this.currentValue = this.value;
  215. } else {
  216. this.currentValue = value;
  217. }
  218. },
  219. handleInput(value) {
  220. this.currentValue = value;
  221. }
  222. }
  223. };
  224. </script>