su-number-box.vue 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  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. // $box-height: 26px;
  186. // $bg: #f5f5f5;
  187. // $br: 2px;
  188. // $color: #333;
  189. // .uni-numbox {
  190. // /* #ifndef APP-NVUE */
  191. // display: flex;
  192. // /* #endif */
  193. // flex-direction: row;
  194. // align-items: center;
  195. // }
  196. // .uni-numbox-btns {
  197. // /* #ifndef APP-NVUE */
  198. // display: flex;
  199. // /* #endif */
  200. // flex-direction: row;
  201. // align-items: center;
  202. // justify-content: center;
  203. // // padding: 0 8rpx;
  204. // width: 40rpx;
  205. // height: 40rpx;
  206. // background-color: $bg;
  207. // /* #ifdef H5 */
  208. // cursor: pointer;
  209. // /* #endif */
  210. // border-radius: 50%;
  211. // }
  212. // .uni-numbox__value {
  213. // // margin: 0 2px;
  214. // // background-color: $bg;
  215. // width: 70rpx;
  216. // height: $box-height;
  217. // text-align: center;
  218. // font-size: 26rpx;
  219. // border-left-width: 0;
  220. // border-right-width: 0;
  221. // color: $color;
  222. // }
  223. // // .uni-numbox__minus {
  224. // // border-top-left-radius: $br;
  225. // // border-bottom-left-radius: $br;
  226. // // }
  227. // .uni-numbox__plus {
  228. // // border-top-right-radius: $br;
  229. // // border-bottom-right-radius: $br;
  230. // background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
  231. // .uni-numbox--text {
  232. // color: $white;
  233. // }
  234. // }
  235. // .uni-numbox--text {
  236. // // fix nvue
  237. // line-height: normal;
  238. // font-size: 40rpx;
  239. // font-weight: 300;
  240. // color: $color;
  241. // }
  242. .uni-numbox .uni-numbox--disabled {
  243. color: #c0c0c0 !important;
  244. /* #ifdef H5 */
  245. cursor: not-allowed;
  246. /* #endif */
  247. }
  248. .uni-numbox {
  249. /* #ifndef APP-NVUE */
  250. display: flex;
  251. /* #endif */
  252. align-items: center;
  253. }
  254. .uni-numbox__value {
  255. width: 70rpx;
  256. text-align: center;
  257. font-size: 26rpx;
  258. }
  259. .cicon-move-round {
  260. font-size: 36rpx;
  261. color: var(--ui-BG-Main);
  262. }
  263. .cicon-add-round {
  264. font-size: 36rpx;
  265. color: var(--ui-BG-Main);
  266. }
  267. .groupon-btn {
  268. color: #ff6000;
  269. }
  270. .seckill-btn {
  271. color: #ff5854;
  272. }
  273. </style>