232 lines
4.8 KiB
Vue
232 lines
4.8 KiB
Vue
<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"
|
|
v-model="currentNum"
|
|
:readOnly="readOnly"
|
|
@blur="$_reset"
|
|
@change="$_onChange">
|
|
</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))
|
|
return (num1 * m + num2 * m) / m
|
|
}
|
|
|
|
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
|
|
return ((num1 * m - num2 * m) / m).toFixed(n)
|
|
}
|
|
|
|
export default {
|
|
name: 'md-stepper',
|
|
|
|
components: {},
|
|
|
|
props: {
|
|
defaultValue: {
|
|
type: Number,
|
|
default: 0,
|
|
},
|
|
step: {
|
|
type: Number,
|
|
default: 1,
|
|
},
|
|
min: {
|
|
type: Number,
|
|
default: -Number.MAX_VALUE,
|
|
},
|
|
max: {
|
|
type: Number,
|
|
default: Number.MAX_VALUE,
|
|
},
|
|
disabled: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
readOnly: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
},
|
|
|
|
data() {
|
|
return {
|
|
isMin: false,
|
|
isMax: false,
|
|
currentNum: 0,
|
|
}
|
|
},
|
|
|
|
watch: {
|
|
defaultValue() {
|
|
this.currentNum = this._getCurrentNum()
|
|
},
|
|
min(val) {
|
|
if (this.currentNum < val) {
|
|
this.currentNum = val
|
|
}
|
|
this.$_checkStatus()
|
|
},
|
|
max(val) {
|
|
if (this.currentNum > val) {
|
|
this.currentNum = val
|
|
}
|
|
this.$_checkStatus()
|
|
},
|
|
},
|
|
|
|
mounted() {
|
|
// verify that the minimum value is less than the maximum value
|
|
this.$_checkMinMax()
|
|
this.currentNum = this.$_getCurrentNum()
|
|
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()
|
|
},
|
|
$_getCurrentNum() {
|
|
let num = this.defaultValue
|
|
if (num < this.min) {
|
|
return this.min
|
|
} else if (num > this.max) {
|
|
return this.max
|
|
} else {
|
|
return this.defaultValue
|
|
}
|
|
},
|
|
$_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
|
|
},
|
|
$_reset() {
|
|
if (!this.currentNum || isNaN(this.currentNum)) {
|
|
this.currentNum = this.min !== -Number.MAX_VALUE ? this.min : 0
|
|
}
|
|
},
|
|
|
|
// MARK: 监听事件方法, 如 $_onButtonClick
|
|
$_onChange() {
|
|
let currentNum = this.currentNum ? this.currentNum : this.min
|
|
if (currentNum < this.min) {
|
|
this.currentNum = this.min
|
|
} else if (currentNum > this.max) {
|
|
this.currentNum = this.max
|
|
}
|
|
this.$_checkStatus()
|
|
this.$emit('change', this.currentNum)
|
|
},
|
|
},
|
|
}
|
|
|
|
</script>
|
|
|
|
<style lang="stylus">
|
|
.md-stepper
|
|
color color-text-base
|
|
-webkit-font-smoothing antialiased
|
|
font-size font-body-large
|
|
height 50px
|
|
display flex
|
|
&.disabled
|
|
opacity opacity-disabled
|
|
.md-stepper-button
|
|
position relative
|
|
width 54px
|
|
height 50px
|
|
background-color color-primary-background
|
|
border-radius 2px
|
|
&:after
|
|
center()
|
|
content ""
|
|
position absolute
|
|
width 24px
|
|
height 2px
|
|
top 50%
|
|
left 50%
|
|
background color-text-base
|
|
transform translate(-50%, -50%)
|
|
&.md-stepper-button-add
|
|
&:before
|
|
center()
|
|
content ""
|
|
position absolute
|
|
width 2px
|
|
height 24px
|
|
top 50%
|
|
left 50%
|
|
background color-text-base
|
|
transform translate(-50%, -50%)
|
|
&.disabled
|
|
opacity opacity-disabled
|
|
.md-stepper-number
|
|
margin 0 4px
|
|
min-width 68px
|
|
height 50px
|
|
padding 0 4px
|
|
text-align center
|
|
border-radius 2px
|
|
input
|
|
width 68px
|
|
height 50px
|
|
border none
|
|
outline none
|
|
font-size font-body-normal
|
|
line-height 50px
|
|
box-sizing border-box
|
|
background-color color-primary-background
|
|
text-align center
|
|
color color-text-base
|
|
border-radius unset
|
|
</style>
|