fx-number-box.vue 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. <template>
  2. <view class="fx-numbox">
  3. <view class="fx-numbox__minus" @tap="_calcValue('minus')" @longpress="_longTapCalcValue('minus')" @touchend="_touchend" @touchcancel ="_touchcancel ">
  4. <view class="icon" :style="{backgroundImage:inputValue > min?'url(../../static/fx-number-box/icon_cancel.png)':'url(../../static/fx-number-box/icon_cancel_invalid.png)'}"></view>
  5. </view>
  6. <input class="fx-numbox__value" type="digit" v-model="inputValue" @blur="_onBlur" @input="onInput">
  7. <view class="fx-numbox__plus" @tap="_calcValue('plus')" @longpress="_longTapCalcValue('plus')" @touchend="_touchend" @touchcancel ="_touchcancel ">
  8. <view class="icon" :style="{backgroundImage:inputValue < max?'url(../../static/fx-number-box/icon_add.png)':'url(../../static/fx-number-box/icon_add-invalid.png)'}"></view>
  9. </view>
  10. </view>
  11. </template>
  12. <script>
  13. window.addEventListener("centextmenu",(e)=>{
  14. e.preventDefault()
  15. })
  16. var timer = null;
  17. export default {
  18. name: 'fx-number-box',
  19. props: {
  20. value: {
  21. type: Number,
  22. default: 0
  23. },
  24. min: {
  25. type: Number,
  26. default: 0
  27. },
  28. max: {
  29. type: Number,
  30. default: 999
  31. },
  32. step: {
  33. type: Number,
  34. default: 1
  35. }
  36. },
  37. data() {
  38. return {
  39. inputValue: 0
  40. }
  41. },
  42. watch: {
  43. value(val) {
  44. this.inputValue = +val;
  45. }
  46. },
  47. methods: {
  48. _calcValue(type) {
  49. const scale = this._getDecimalScale();
  50. let value = this.inputValue * scale
  51. let step = this.step * scale
  52. if (type === 'minus') {
  53. value -= step
  54. if (value < this.min) {
  55. value = this.min
  56. }
  57. } else if (type === 'plus') {
  58. value += step
  59. if (value > this.max) {
  60. value = this.max
  61. }
  62. }
  63. this.inputValue = Math.floor((value/scale).toFixed(1)*10)/10;
  64. this.$emit('change', this.inputValue);
  65. },
  66. onInput(e){
  67. this.inputValue = Math.floor(Number(e.detail.value).toFixed(1)*10)/10;
  68. this.$emit('change', this.inputValue);
  69. },
  70. _longTapCalcValue(type) {
  71. var _this = this;
  72. timer = setInterval(function(){
  73. const scale = _this._getDecimalScale()
  74. let value = _this.inputValue * scale
  75. let step = _this.step * scale
  76. if (type === 'minus') {
  77. value -= step
  78. if (value < _this.min) {
  79. value = _this.min;
  80. clearInterval(timer)
  81. return false
  82. }
  83. } else if (type === 'plus') {
  84. value += step
  85. if (value > _this.max) {
  86. value = _this.max
  87. clearInterval(timer)
  88. return false
  89. }
  90. }
  91. _this.inputValue = Math.floor((value/scale).toFixed(1)*10)/10;
  92. _this.$emit('change', _this.inputValue);
  93. },150)
  94. },
  95. _touchend(){
  96. clearInterval(timer)
  97. },
  98. _touchcancel(){
  99. clearInterval(timer)
  100. },
  101. _getDecimalScale() {
  102. let scale = 1
  103. // 浮点型
  104. if (~~this.step !== this.step) {
  105. scale = Math.pow(10, (this.step + '').split('.')[1].length)
  106. }
  107. return scale
  108. },
  109. _onBlur(event) {
  110. let value = event.detail.value
  111. if (!value) {
  112. this.inputValue = 0
  113. return
  114. }
  115. value = +value;
  116. if (value > this.max) {
  117. value = this.max
  118. } else if (value < this.min) {
  119. value = this.min
  120. }
  121. this.inputValue = value
  122. }
  123. },
  124. created() {
  125. this.inputValue = +this.value;
  126. }
  127. }
  128. </script>
  129. <style lang="scss">
  130. .fx-numbox {
  131. display: inline-flex;
  132. flex-direction: row;
  133. justify-content: flex-start;
  134. height:60rpx;
  135. position: relative;
  136. &__minus,
  137. &__plus {
  138. margin: 0;
  139. width:60rpx;
  140. height: 60rpx;
  141. display: flex;
  142. justify-content: center;
  143. align-items: center;
  144. .icon{
  145. width: 40rpx;
  146. height: 40rpx;
  147. background-position: center center;
  148. background-repeat: no-repeat;
  149. background-size: cover;
  150. pointer-events: none;
  151. }
  152. }
  153. &__value {
  154. width: 100rpx;
  155. height:60rpx;
  156. text-align: center;
  157. padding: 0;
  158. }
  159. }
  160. </style>