index.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. import { VantComponent } from '../common/component';
  2. import { isDef } from '../common/utils';
  3. const LONG_PRESS_START_TIME = 600;
  4. const LONG_PRESS_INTERVAL = 200;
  5. // add num and avoid float number
  6. function add(num1, num2) {
  7. const cardinal = Math.pow(10, 10);
  8. return Math.round((num1 + num2) * cardinal) / cardinal;
  9. }
  10. function equal(value1, value2) {
  11. return String(value1) === String(value2);
  12. }
  13. VantComponent({
  14. field: true,
  15. classes: ['input-class', 'plus-class', 'minus-class'],
  16. props: {
  17. value: {
  18. type: null,
  19. observer(value) {
  20. if (!equal(value, this.data.currentValue)) {
  21. this.setData({ currentValue: this.format(value) });
  22. }
  23. },
  24. },
  25. integer: {
  26. type: Boolean,
  27. observer: 'check',
  28. },
  29. disabled: Boolean,
  30. inputWidth: null,
  31. buttonSize: null,
  32. asyncChange: Boolean,
  33. disableInput: Boolean,
  34. decimalLength: {
  35. type: Number,
  36. value: null,
  37. observer: 'check',
  38. },
  39. min: {
  40. type: null,
  41. value: 1,
  42. observer: 'check',
  43. },
  44. max: {
  45. type: null,
  46. value: Number.MAX_SAFE_INTEGER,
  47. observer: 'check',
  48. },
  49. step: {
  50. type: null,
  51. value: 1,
  52. },
  53. showPlus: {
  54. type: Boolean,
  55. value: true,
  56. },
  57. showMinus: {
  58. type: Boolean,
  59. value: true,
  60. },
  61. disablePlus: Boolean,
  62. disableMinus: Boolean,
  63. longPress: {
  64. type: Boolean,
  65. value: true,
  66. },
  67. },
  68. data: {
  69. currentValue: '',
  70. },
  71. created() {
  72. this.setData({
  73. currentValue: this.format(this.data.value),
  74. });
  75. },
  76. methods: {
  77. check() {
  78. const val = this.format(this.data.currentValue);
  79. if (!equal(val, this.data.currentValue)) {
  80. this.setData({ currentValue: val });
  81. }
  82. },
  83. isDisabled(type) {
  84. if (type === 'plus') {
  85. return (
  86. this.data.disabled ||
  87. this.data.disablePlus ||
  88. this.data.currentValue >= this.data.max
  89. );
  90. }
  91. return (
  92. this.data.disabled ||
  93. this.data.disableMinus ||
  94. this.data.currentValue <= this.data.min
  95. );
  96. },
  97. onFocus(event) {
  98. this.$emit('focus', event.detail);
  99. },
  100. onBlur(event) {
  101. const value = this.format(event.detail.value);
  102. this.emitChange(value);
  103. this.$emit(
  104. 'blur',
  105. Object.assign(Object.assign({}, event.detail), { value })
  106. );
  107. },
  108. // filter illegal characters
  109. filter(value) {
  110. value = String(value).replace(/[^0-9.-]/g, '');
  111. if (this.data.integer && value.indexOf('.') !== -1) {
  112. value = value.split('.')[0];
  113. }
  114. return value;
  115. },
  116. // limit value range
  117. format(value) {
  118. value = this.filter(value);
  119. // format range
  120. value = value === '' ? 0 : +value;
  121. value = Math.max(Math.min(this.data.max, value), this.data.min);
  122. // format decimal
  123. if (isDef(this.data.decimalLength)) {
  124. value = value.toFixed(this.data.decimalLength);
  125. }
  126. return value;
  127. },
  128. onInput(event) {
  129. const { value = '' } = event.detail || {};
  130. // allow input to be empty
  131. if (value === '') {
  132. return;
  133. }
  134. let formatted = this.filter(value);
  135. // limit max decimal length
  136. if (isDef(this.data.decimalLength) && formatted.indexOf('.') !== -1) {
  137. const pair = formatted.split('.');
  138. formatted = `${pair[0]}.${pair[1].slice(0, this.data.decimalLength)}`;
  139. }
  140. this.emitChange(formatted);
  141. },
  142. emitChange(value) {
  143. if (!this.data.asyncChange) {
  144. this.setData({ currentValue: value });
  145. }
  146. this.$emit('change', value);
  147. },
  148. onChange() {
  149. const { type } = this;
  150. if (this.isDisabled(type)) {
  151. this.$emit('overlimit', type);
  152. return;
  153. }
  154. const diff = type === 'minus' ? -this.data.step : +this.data.step;
  155. const value = this.format(add(+this.data.currentValue, diff));
  156. this.emitChange(value);
  157. this.$emit(type);
  158. },
  159. longPressStep() {
  160. this.longPressTimer = setTimeout(() => {
  161. this.onChange();
  162. this.longPressStep();
  163. }, LONG_PRESS_INTERVAL);
  164. },
  165. onTap(event) {
  166. const { type } = event.currentTarget.dataset;
  167. this.type = type;
  168. this.onChange();
  169. },
  170. onTouchStart(event) {
  171. if (!this.data.longPress) {
  172. return;
  173. }
  174. clearTimeout(this.longPressTimer);
  175. const { type } = event.currentTarget.dataset;
  176. this.type = type;
  177. this.isLongPress = false;
  178. this.longPressTimer = setTimeout(() => {
  179. this.isLongPress = true;
  180. this.onChange();
  181. this.longPressStep();
  182. }, LONG_PRESS_START_TIME);
  183. },
  184. onTouchEnd() {
  185. if (!this.data.longPress) {
  186. return;
  187. }
  188. clearTimeout(this.longPressTimer);
  189. },
  190. },
  191. });