| 
									
										
										
										
											2018-03-26 16:04:04 +08:00
										 |  |  | <template> | 
					
						
							|  |  |  |   <div | 
					
						
							|  |  |  |     class="md-stepper" | 
					
						
							|  |  |  |     :class="{'disabled': disabled}" | 
					
						
							|  |  |  |   > | 
					
						
							|  |  |  |     <div | 
					
						
							|  |  |  |       class="md-stepper-button md-stepper-button-reduce" | 
					
						
							|  |  |  |       :class="{'disabled': isMin}" | 
					
						
							|  |  |  |       @click="$_reduce" | 
					
						
							|  |  |  |     > | 
					
						
							|  |  |  |     </div> | 
					
						
							|  |  |  |     <div class="md-stepper-number"> | 
					
						
							|  |  |  |       <input type="tel" | 
					
						
							| 
									
										
										
										
											2018-08-29 14:21:07 +08:00
										 |  |  |         :size="contentLength" | 
					
						
							| 
									
										
										
										
											2018-07-31 22:45:27 +08:00
										 |  |  |         :value="currentNum" | 
					
						
							|  |  |  |         :readOnly="readOnly" | 
					
						
							|  |  |  |         @input="$_onInput" | 
					
						
							|  |  |  |         @blur="$_onChange"> | 
					
						
							| 
									
										
										
										
											2018-03-26 16:04:04 +08:00
										 |  |  |     </div> | 
					
						
							|  |  |  |     <div | 
					
						
							|  |  |  |       class="md-stepper-button md-stepper-button-add" | 
					
						
							|  |  |  |       :class="{'disabled': isMax}" | 
					
						
							|  |  |  |       @click="$_add" | 
					
						
							|  |  |  |     > | 
					
						
							|  |  |  |     </div> | 
					
						
							|  |  |  |   </div> | 
					
						
							|  |  |  | </template> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <script>
import {warn} from '../_util' | 
					
						
							|  |  |  | function getDecimalNum(num) { | 
					
						
							|  |  |  |   try { | 
					
						
							|  |  |  |     return num.toString().split('.')[1].length | 
					
						
							|  |  |  |   } catch (e) { | 
					
						
							|  |  |  |     return 0 | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function accAdd(num1, num2) { | 
					
						
							|  |  |  |   let r1 = getDecimalNum(num1) | 
					
						
							|  |  |  |   let r2 = getDecimalNum(num2) | 
					
						
							|  |  |  |   let m = Math.pow(10, Math.max(r1, r2)) | 
					
						
							| 
									
										
										
										
											2018-07-31 22:45:27 +08:00
										 |  |  |   return +((num1 * m + num2 * m) / m) | 
					
						
							| 
									
										
										
										
											2018-03-26 16:04:04 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function subtr(num1, num2) { | 
					
						
							|  |  |  |   let r1 = getDecimalNum(num1) | 
					
						
							|  |  |  |   let r2 = getDecimalNum(num2) | 
					
						
							|  |  |  |   let m = Math.pow(10, Math.max(r1, r2)) | 
					
						
							|  |  |  |   let n = r1 >= r2 ? r1 : r2 | 
					
						
							| 
									
										
										
										
											2018-07-31 22:45:27 +08:00
										 |  |  |   return +((num1 * m - num2 * m) / m).toFixed(n) | 
					
						
							| 
									
										
										
										
											2018-03-26 16:04:04 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export default { | 
					
						
							|  |  |  |   name: 'md-stepper', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   components: {}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   props: { | 
					
						
							|  |  |  |     defaultValue: { | 
					
						
							| 
									
										
										
										
											2018-07-31 22:45:27 +08:00
										 |  |  |       type: [Number, String], | 
					
						
							|  |  |  |       default: 0, | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     value: { | 
					
						
							|  |  |  |       type: [Number, String], | 
					
						
							| 
									
										
										
										
											2018-03-26 16:04:04 +08:00
										 |  |  |       default: 0, | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     step: { | 
					
						
							| 
									
										
										
										
											2018-07-31 22:45:27 +08:00
										 |  |  |       type: [Number, String], | 
					
						
							| 
									
										
										
										
											2018-03-26 16:04:04 +08:00
										 |  |  |       default: 1, | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     min: { | 
					
						
							| 
									
										
										
										
											2018-07-31 22:45:27 +08:00
										 |  |  |       type: [Number, String], | 
					
						
							| 
									
										
										
										
											2018-03-26 16:04:04 +08:00
										 |  |  |       default: -Number.MAX_VALUE, | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     max: { | 
					
						
							| 
									
										
										
										
											2018-07-31 22:45:27 +08:00
										 |  |  |       type: [Number, String], | 
					
						
							| 
									
										
										
										
											2018-03-26 16:04:04 +08:00
										 |  |  |       default: Number.MAX_VALUE, | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     disabled: { | 
					
						
							|  |  |  |       type: Boolean, | 
					
						
							|  |  |  |       default: false, | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     readOnly: { | 
					
						
							|  |  |  |       type: Boolean, | 
					
						
							|  |  |  |       default: false, | 
					
						
							|  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2018-07-31 22:45:27 +08:00
										 |  |  |     isInteger: { | 
					
						
							|  |  |  |       type: Boolean, | 
					
						
							|  |  |  |       default: false, | 
					
						
							|  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2018-03-26 16:04:04 +08:00
										 |  |  |   }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   data() { | 
					
						
							|  |  |  |     return { | 
					
						
							|  |  |  |       isMin: false, | 
					
						
							|  |  |  |       isMax: false, | 
					
						
							|  |  |  |       currentNum: 0, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-29 14:21:07 +08:00
										 |  |  |   computed: { | 
					
						
							|  |  |  |     contentLength() { | 
					
						
							|  |  |  |       if (!this.value) { | 
					
						
							|  |  |  |         return 2 | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       const length = this.value.toString().length | 
					
						
							|  |  |  |       return length > 2 ? length : 2 | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-26 16:04:04 +08:00
										 |  |  |   watch: { | 
					
						
							| 
									
										
										
										
											2018-07-31 22:45:27 +08:00
										 |  |  |     defaultValue(val) { | 
					
						
							|  |  |  |       this.currentNum = this.$_getCurrentNum(val) | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     value(val) { | 
					
						
							|  |  |  |       this.currentNum = this.$_getCurrentNum(val) | 
					
						
							| 
									
										
										
										
											2018-03-26 16:04:04 +08:00
										 |  |  |     }, | 
					
						
							|  |  |  |     min(val) { | 
					
						
							|  |  |  |       if (this.currentNum < val) { | 
					
						
							|  |  |  |         this.currentNum = val | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       this.$_checkStatus() | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     max(val) { | 
					
						
							|  |  |  |       if (this.currentNum > val) { | 
					
						
							|  |  |  |         this.currentNum = val | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       this.$_checkStatus() | 
					
						
							|  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2019-04-10 15:20:19 +08:00
										 |  |  |     currentNum(val, oldVal) { | 
					
						
							| 
									
										
										
										
											2018-07-31 22:45:27 +08:00
										 |  |  |       this.$_checkStatus() | 
					
						
							| 
									
										
										
										
											2019-04-10 15:20:19 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-29 10:42:02 +08:00
										 |  |  |       if (val !== this.value) { | 
					
						
							|  |  |  |         this.$emit('input', val) | 
					
						
							|  |  |  |         this.$emit('change', val) | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-04-10 15:20:19 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |       const diff = val - oldVal | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // judge the event of operation
 | 
					
						
							|  |  |  |       if (diff > 0) { | 
					
						
							|  |  |  |         this.$emit('increase', diff) | 
					
						
							|  |  |  |       } else if (diff < 0) { | 
					
						
							|  |  |  |         this.$emit('decrease', Math.abs(diff)) | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-07-31 22:45:27 +08:00
										 |  |  |     }, | 
					
						
							| 
									
										
										
										
											2018-03-26 16:04:04 +08:00
										 |  |  |   }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   mounted() { | 
					
						
							|  |  |  |     // verify that the minimum value is less than the maximum value
 | 
					
						
							|  |  |  |     this.$_checkMinMax() | 
					
						
							| 
									
										
										
										
											2018-07-31 22:45:27 +08:00
										 |  |  |     this.currentNum = this.$_getCurrentNum(this.value || this.defaultValue) | 
					
						
							| 
									
										
										
										
											2018-03-26 16:04:04 +08:00
										 |  |  |     this.$_checkStatus() | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   methods: { | 
					
						
							|  |  |  |     // MARK: 私有方法
 | 
					
						
							|  |  |  |     $_reduce() { | 
					
						
							|  |  |  |       if (this.disabled || this.isMin) { | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       this.currentNum = subtr(this.currentNum, this.step) | 
					
						
							|  |  |  |       this.$_onChange() | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     $_add() { | 
					
						
							|  |  |  |       if (this.disabled || this.isMax) { | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       this.currentNum = accAdd(this.currentNum, this.step) | 
					
						
							|  |  |  |       this.$_onChange() | 
					
						
							|  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2018-07-31 22:45:27 +08:00
										 |  |  |     $_formatNum(value) { | 
					
						
							|  |  |  |       // @elist
 | 
					
						
							|  |  |  |       value = String(value).replace(/[^0-9.-]/g, '') | 
					
						
							|  |  |  |       return value === '' ? 0 : this.isInteger ? Math.floor(value) : +value | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     $_getCurrentNum(value) { | 
					
						
							|  |  |  |       return Math.max(Math.min(this.max, this.$_formatNum(value)), this.min) | 
					
						
							| 
									
										
										
										
											2018-03-26 16:04:04 +08:00
										 |  |  |     }, | 
					
						
							|  |  |  |     $_checkStatus() { | 
					
						
							|  |  |  |       this.isMin = subtr(this.currentNum, this.step) < this.min | 
					
						
							|  |  |  |       this.isMax = accAdd(this.currentNum, this.step) > this.max | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     $_checkMinMax() { | 
					
						
							|  |  |  |       if (this.min > this.max) { | 
					
						
							|  |  |  |         warn('[md-vue-stepper] minNum is larger than maxNum') | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       return this.max > this.min | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // MARK: 监听事件方法, 如 $_onButtonClick
 | 
					
						
							| 
									
										
										
										
											2018-07-31 22:45:27 +08:00
										 |  |  |     $_onInput(event) { | 
					
						
							|  |  |  |       const {value} = event.target | 
					
						
							|  |  |  |       const formatted = this.$_formatNum(value) | 
					
						
							|  |  |  |       if (+value !== formatted) { | 
					
						
							|  |  |  |         event.target.value = formatted | 
					
						
							| 
									
										
										
										
											2018-03-26 16:04:04 +08:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-07-31 22:45:27 +08:00
										 |  |  |       this.currentNum = formatted | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     $_onChange() { | 
					
						
							|  |  |  |       this.currentNum = this.$_getCurrentNum(this.currentNum) | 
					
						
							| 
									
										
										
										
											2018-03-26 16:04:04 +08:00
										 |  |  |     }, | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
</script> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <style lang="stylus"> | 
					
						
							|  |  |  | .md-stepper | 
					
						
							| 
									
										
										
										
											2018-06-05 18:34:40 +08:00
										 |  |  |   color stepper-color | 
					
						
							| 
									
										
										
										
											2018-03-26 16:04:04 +08:00
										 |  |  |   -webkit-font-smoothing antialiased | 
					
						
							| 
									
										
										
										
											2018-06-05 18:34:40 +08:00
										 |  |  |   font-size stepper-font-size | 
					
						
							|  |  |  |   height stepper-height | 
					
						
							| 
									
										
										
										
											2018-03-26 16:04:04 +08:00
										 |  |  |   display flex | 
					
						
							|  |  |  |   &.disabled | 
					
						
							| 
									
										
										
										
											2018-08-29 14:21:07 +08:00
										 |  |  |     .md-stepper-button | 
					
						
							|  |  |  |       &:before, | 
					
						
							|  |  |  |       &:after | 
					
						
							|  |  |  |         opacity stepper-disabled-opacity | 
					
						
							|  |  |  |     input | 
					
						
							|  |  |  |       opacity stepper-disabled-opacity | 
					
						
							| 
									
										
										
										
											2018-09-03 17:28:32 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | .md-stepper-button | 
					
						
							|  |  |  |   position relative | 
					
						
							|  |  |  |   width stepper-width-button | 
					
						
							|  |  |  |   height stepper-height | 
					
						
							|  |  |  |   background-color stepper-fill | 
					
						
							| 
									
										
										
										
											2019-07-09 15:56:25 +08:00
										 |  |  |   border-radius stepper-radius-button | 
					
						
							| 
									
										
										
										
											2018-09-03 17:28:32 +08:00
										 |  |  |   &:after | 
					
						
							|  |  |  |     content "" | 
					
						
							|  |  |  |     position absolute | 
					
						
							|  |  |  |     width 24px | 
					
						
							|  |  |  |     height 2px | 
					
						
							|  |  |  |     top 50% | 
					
						
							|  |  |  |     left 50% | 
					
						
							|  |  |  |     background stepper-color | 
					
						
							|  |  |  |     transform translate(-50%, -50%) | 
					
						
							|  |  |  |   &.md-stepper-button-add | 
					
						
							|  |  |  |     &:before | 
					
						
							| 
									
										
										
										
											2018-03-26 16:04:04 +08:00
										 |  |  |       content "" | 
					
						
							|  |  |  |       position absolute | 
					
						
							| 
									
										
										
										
											2018-09-03 17:28:32 +08:00
										 |  |  |       width 2px | 
					
						
							|  |  |  |       height 24px | 
					
						
							| 
									
										
										
										
											2018-03-26 16:04:04 +08:00
										 |  |  |       top 50% | 
					
						
							|  |  |  |       left 50% | 
					
						
							| 
									
										
										
										
											2018-06-05 18:34:40 +08:00
										 |  |  |       background stepper-color | 
					
						
							| 
									
										
										
										
											2018-03-26 16:04:04 +08:00
										 |  |  |       transform translate(-50%, -50%) | 
					
						
							| 
									
										
										
										
											2018-09-03 17:28:32 +08:00
										 |  |  |   &.disabled | 
					
						
							|  |  |  |     &:before, | 
					
						
							|  |  |  |     &:after | 
					
						
							|  |  |  |       opacity stepper-disabled-opacity | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | .md-stepper-number | 
					
						
							|  |  |  |   margin 0 4px | 
					
						
							|  |  |  |   min-width stepper-width-input | 
					
						
							|  |  |  |   height stepper-height | 
					
						
							|  |  |  |   padding 0 4px | 
					
						
							|  |  |  |   text-align center | 
					
						
							| 
									
										
										
										
											2019-07-09 15:56:25 +08:00
										 |  |  |   border-radius stepper-radius-input | 
					
						
							| 
									
										
										
										
											2018-09-03 17:28:32 +08:00
										 |  |  |   background-color stepper-fill | 
					
						
							|  |  |  |   input | 
					
						
							|  |  |  |     width 100% | 
					
						
							| 
									
										
										
										
											2018-06-05 18:34:40 +08:00
										 |  |  |     height stepper-height | 
					
						
							| 
									
										
										
										
											2018-09-03 17:28:32 +08:00
										 |  |  |     border none | 
					
						
							|  |  |  |     outline none | 
					
						
							|  |  |  |     font-size stepper-input-font-size | 
					
						
							|  |  |  |     line-height stepper-height | 
					
						
							|  |  |  |     background-color transparent | 
					
						
							|  |  |  |     box-sizing border-box | 
					
						
							| 
									
										
										
										
											2018-03-26 16:04:04 +08:00
										 |  |  |     text-align center | 
					
						
							| 
									
										
										
										
											2018-09-03 17:28:32 +08:00
										 |  |  |     color stepper-color | 
					
						
							| 
									
										
										
										
											2018-03-26 16:04:04 +08:00
										 |  |  | </style> |