su-number-box.vue 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. <template>
  2. <view class="uni-numbox">
  3. <!-- <view @click="_calcValue('minus')" class="uni-numbox__minus uni-numbox-btns" :style="{ background }"> -->
  4. <!-- <text class="uni-numbox--text" :class="{ 'uni-numbox--disabled': inputValue <= min || disabled }"
  5. :style="{ color }">
  6. -
  7. </text> -->
  8. <text
  9. class="cicon-move-round"
  10. :class="{
  11. 'uni-numbox--disabled': inputValue <= min || disabled,
  12. 'groupon-btn': activity === 'groupon',
  13. 'seckill-btn': activity === 'seckill',
  14. }"
  15. @click="_calcValue('minus')"
  16. ></text>
  17. <!-- </view> -->
  18. <input
  19. :disabled="disabled"
  20. @focus="_onFocus"
  21. @blur="_onBlur"
  22. class="uni-numbox__value"
  23. type="number"
  24. v-model="inputValue"
  25. :style="{ color }"
  26. />
  27. <!-- <view @click="_calcValue('plus')" class="uni-numbox__plus uni-numbox-btns">
  28. <text class="uni-numbox--text" :class="{ 'uni-numbox--disabled': inputValue >= max || disabled }">+</text>
  29. </view> -->
  30. <text
  31. class="cicon-add-round"
  32. :class="{
  33. 'uni-numbox--disabled': inputValue >= max || disabled,
  34. 'groupon-btn': activity === 'groupon',
  35. 'seckill-btn': activity === 'seckill',
  36. }"
  37. @click="_calcValue('plus')"
  38. ></text>
  39. </view>
  40. </template>
  41. <script>
  42. /**
  43. * NumberBox 数字输入框
  44. * @description 带加减按钮的数字输入框
  45. * @tutorial https://ext.dcloud.net.cn/plugin?id=31
  46. * @property {Number} value 输入框当前值
  47. * @property {Number} min 最小值
  48. * @property {Number} max 最大值
  49. * @property {Number} step 每次点击改变的间隔大小
  50. * @property {String} background 背景色
  51. * @property {String} color 字体颜色(前景色)
  52. * @property {Boolean} disabled = [true|false] 是否为禁用状态
  53. * @event {Function} change 输入框值改变时触发的事件,参数为输入框当前的 value
  54. * @event {Function} focus 输入框聚焦时触发的事件,参数为 event 对象
  55. * @event {Function} blur 输入框失焦时触发的事件,参数为 event 对象
  56. */
  57. export default {
  58. name: 'UniNumberBox',
  59. emits: ['change', 'input', 'update:modelValue', 'blur', 'focus'],
  60. props: {
  61. value: {
  62. type: [Number, String],
  63. default: 1,
  64. },
  65. modelValue: {
  66. type: [Number, String],
  67. default: 1,
  68. },
  69. min: {
  70. type: Number,
  71. default: 0,
  72. },
  73. max: {
  74. type: Number,
  75. default: 100,
  76. },
  77. step: {
  78. type: Number,
  79. default: 1,
  80. },
  81. background: {
  82. type: String,
  83. default: '#f5f5f5',
  84. },
  85. color: {
  86. type: String,
  87. default: '#333',
  88. },
  89. disabled: {
  90. type: Boolean,
  91. default: false,
  92. },
  93. activity: {
  94. type: String,
  95. default: 'none',
  96. },
  97. },
  98. data() {
  99. return {
  100. inputValue: 0,
  101. };
  102. },
  103. watch: {
  104. value(val) {
  105. this.inputValue = +val;
  106. },
  107. modelValue(val) {
  108. this.inputValue = +val;
  109. },
  110. },
  111. created() {
  112. if (this.value === 1) {
  113. this.inputValue = +this.modelValue;
  114. }
  115. if (this.modelValue === 1) {
  116. this.inputValue = +this.value;
  117. }
  118. },
  119. methods: {
  120. _calcValue(type) {
  121. if (this.disabled) {
  122. return;
  123. }
  124. const scale = this._getDecimalScale();
  125. let value = this.inputValue * scale;
  126. let step = this.step * scale;
  127. if (type === 'minus') {
  128. value -= step;
  129. if (value < this.min * scale) {
  130. return;
  131. }
  132. if (value > this.max * scale) {
  133. value = this.max * scale;
  134. }
  135. }
  136. if (type === 'plus') {
  137. value += step;
  138. if (value > this.max * scale) {
  139. return;
  140. }
  141. if (value < this.min * scale) {
  142. value = this.min * scale;
  143. }
  144. }
  145. this.inputValue = (value / scale).toFixed(String(scale).length - 1);
  146. this.$emit('change', +this.inputValue);
  147. // TODO vue2 兼容
  148. this.$emit('input', +this.inputValue);
  149. // TODO vue3 兼容
  150. this.$emit('update:modelValue', +this.inputValue);
  151. },
  152. _getDecimalScale() {
  153. let scale = 1;
  154. // 浮点型
  155. if (~~this.step !== this.step) {
  156. scale = Math.pow(10, String(this.step).split('.')[1].length);
  157. }
  158. return scale;
  159. },
  160. _onBlur(event) {
  161. this.$emit('blur', event);
  162. let value = event.detail.value;
  163. if (!value) {
  164. // this.inputValue = 0;
  165. return;
  166. }
  167. value = +value;
  168. if (value > this.max) {
  169. value = this.max;
  170. } else if (value < this.min) {
  171. value = this.min;
  172. }
  173. const scale = this._getDecimalScale();
  174. this.inputValue = value.toFixed(String(scale).length - 1);
  175. this.$emit('change', +this.inputValue);
  176. this.$emit('input', +this.inputValue);
  177. },
  178. _onFocus(event) {
  179. this.$emit('focus', event);
  180. },
  181. },
  182. };
  183. </script>
  184. <style lang="scss" scoped>
  185. .uni-numbox .uni-numbox--disabled {
  186. color: #c0c0c0 !important;
  187. /* #ifdef H5 */
  188. cursor: not-allowed;
  189. /* #endif */
  190. }
  191. .uni-numbox {
  192. /* #ifndef APP-NVUE */
  193. display: flex;
  194. /* #endif */
  195. align-items: center;
  196. }
  197. .uni-numbox__value {
  198. width: 74rpx;
  199. text-align: center;
  200. font-size: 30rpx;
  201. }
  202. .cicon-move-round {
  203. font-size: 44rpx;
  204. color: var(--ui-BG-Main);
  205. }
  206. .cicon-add-round {
  207. font-size: 44rpx;
  208. color: var(--ui-BG-Main);
  209. }
  210. .groupon-btn {
  211. color: #ff6000;
  212. }
  213. .seckill-btn {
  214. color: #ff5854;
  215. }
  216. </style>