¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="u-number-box"> |
| | | <view |
| | | class="u-number-box__slot" |
| | | @tap.stop="clickHandler('minus')" |
| | | @touchstart="onTouchStart('minus')" |
| | | @touchend.stop="clearTimeout" |
| | | v-if="showMinus && $slots.minus" |
| | | > |
| | | <slot name="minus" /> |
| | | </view> |
| | | <view |
| | | v-else-if="showMinus" |
| | | class="u-number-box__minus" |
| | | @tap.stop="clickHandler('minus')" |
| | | @touchstart="onTouchStart('minus')" |
| | | @touchend.stop="clearTimeout" |
| | | hover-class="u-number-box__minus--hover" |
| | | hover-stay-time="150" |
| | | :class="{ 'u-number-box__minus--disabled': isDisabled('minus') }" |
| | | :style="[buttonStyle('minus')]" |
| | | > |
| | | <u-icon |
| | | name="minus" |
| | | :color="isDisabled('minus') ? '#c8c9cc' : '#323233'" |
| | | size="15" |
| | | bold |
| | | :customStyle="iconStyle" |
| | | ></u-icon> |
| | | </view> |
| | | |
| | | <slot name="input"> |
| | | <input |
| | | :disabled="disabledInput || disabled" |
| | | :cursor-spacing="getCursorSpacing" |
| | | :class="{ 'u-number-box__input--disabled': disabled || disabledInput }" |
| | | v-model="currentValue" |
| | | class="u-number-box__input" |
| | | @blur="onBlur" |
| | | @focus="onFocus" |
| | | @input="onInput" |
| | | type="number" |
| | | :style="[inputStyle]" |
| | | /> |
| | | </slot> |
| | | <view |
| | | class="u-number-box__slot" |
| | | @tap.stop="clickHandler('plus')" |
| | | @touchstart="onTouchStart('plus')" |
| | | @touchend.stop="clearTimeout" |
| | | v-if="showPlus && $slots.plus" |
| | | > |
| | | <slot name="plus" /> |
| | | </view> |
| | | <view |
| | | v-else-if="showPlus" |
| | | class="u-number-box__plus" |
| | | @tap.stop="clickHandler('plus')" |
| | | @touchstart="onTouchStart('plus')" |
| | | @touchend.stop="clearTimeout" |
| | | hover-class="u-number-box__plus--hover" |
| | | hover-stay-time="150" |
| | | :class="{ 'u-number-box__minus--disabled': isDisabled('plus') }" |
| | | :style="[buttonStyle('plus')]" |
| | | > |
| | | <u-icon |
| | | name="plus" |
| | | :color="isDisabled('plus') ? '#c8c9cc' : '#323233'" |
| | | size="15" |
| | | bold |
| | | :customStyle="iconStyle" |
| | | ></u-icon> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script> |
| | | import props from './props.js'; |
| | | /** |
| | | * numberBox æ¥è¿å¨ |
| | | * @description 该ç»ä»¶ä¸è¬ç¨äºååè´ç©éæ©ç©åæ°éçåºæ¯ã |
| | | * @tutorial https://uviewui.com/components/numberBox.html |
| | | * @property {String | Number} name æ¥è¿å¨æ è¯ç¬¦ï¼å¨changeåè°è¿å |
| | | * @property {String | Number} value ç¨äºååç»å®çå¼ï¼åå§åæ¶è®¾ç½®è®¾ä¸ºé»è®¤minå¼(æå°å¼) ï¼é»è®¤ 0 ï¼ |
| | | * @property {String | Number} min æå°å¼ ï¼é»è®¤ 1 ï¼ |
| | | * @property {String | Number} max æå¤§å¼ ï¼é»è®¤ Number.MAX_SAFE_INTEGER ï¼ |
| | | * @property {String | Number} step å åçæ¥é¿ï¼å¯ä¸ºå°æ° ï¼é»è®¤ 1 ï¼ |
| | | * @property {Boolean} integer æ¯å¦åªå
许è¾å
¥æ´æ° ï¼é»è®¤ false ï¼ |
| | | * @property {Boolean} disabled æ¯å¦ç¦ç¨ï¼å
æ¬è¾å
¥æ¡ï¼å åæé® ï¼é»è®¤ false ï¼ |
| | | * @property {Boolean} disabledInput æ¯å¦ç¦ç¨è¾å
¥æ¡ ï¼é»è®¤ false ï¼ |
| | | * @property {Boolean} asyncChange æ¯å¦å¼å¯å¼æ¥åæ´ï¼å¼å¯åéè¦æå¨æ§å¶è¾å
¥å¼ ï¼é»è®¤ false ï¼ |
| | | * @property {String | Number} inputWidth è¾å
¥æ¡å®½åº¦ï¼åä½ä¸ºpx ï¼é»è®¤ 35 ï¼ |
| | | * @property {Boolean} showMinus æ¯å¦æ¾ç¤ºåå°æé® ï¼é»è®¤ true ï¼ |
| | | * @property {Boolean} showPlus æ¯å¦æ¾ç¤ºå¢å æé® ï¼é»è®¤ true ï¼ |
| | | * @property {String | Number} decimalLength æ¾ç¤ºçå°æ°ä½æ° |
| | | * @property {Boolean} longPress æ¯å¦å¼å¯é¿æå åæå¿ ï¼é»è®¤ true ï¼ |
| | | * @property {String} color è¾å
¥æ¡æååå åæé®å¾æ çé¢è² ï¼é»è®¤ '#323233' ï¼ |
| | | * @property {String | Number} buttonSize æé®å¤§å°ï¼å®½é«çäºæ¤å¼ï¼åä½pxï¼è¾å
¥æ¡é«åº¦åæ¤å¼ä¿æä¸è´ ï¼é»è®¤ 30 ï¼ |
| | | * @property {String} bgColor è¾å
¥æ¡åæé®çèæ¯é¢è² ï¼é»è®¤ '#EBECEE' ï¼ |
| | | * @property {String | Number} cursorSpacing æå®å
æ äºé®ççè·ç¦»ï¼é¿å
é®ç鮿¡è¾å
¥æ¡ï¼åä½px ï¼é»è®¤ 100 ï¼ |
| | | * @property {Boolean} disablePlus æ¯å¦ç¦ç¨å¢å æé® ï¼é»è®¤ false ï¼ |
| | | * @property {Boolean} disableMinus æ¯å¦ç¦ç¨åå°æé® ï¼é»è®¤ false ï¼ |
| | | * @property {Object ï½ String} iconStyle å åæé®å¾æ çæ ·å¼ |
| | | * |
| | | * @event {Function} onFocus è¾å
¥æ¡æ´»å¨ç¦ç¹ |
| | | * @event {Function} onBlur è¾å
¥æ¡å¤±å»ç¦ç¹ |
| | | * @event {Function} onInput è¾å
¥æ¡å¼åçåå |
| | | * @event {Function} onChange |
| | | * @example <u-number-box v-model="value" @change="valChange"></u-number-box> |
| | | */ |
| | | export default { |
| | | name: 'u-number-box', |
| | | mixins: [uni.$u.mpMixin, uni.$u.mixin, props], |
| | | data() { |
| | | return { |
| | | // è¾å
¥æ¡å®é
æä½çå¼ |
| | | currentValue: '', |
| | | // 宿¶å¨ |
| | | longPressTimer: null |
| | | } |
| | | }, |
| | | watch: { |
| | | // å¤ä¸ªå¼ä¹é´ï¼åªè¦ä¸ä¸ªå¼åçååï¼é½è¦éæ°æ£æ¥check()彿° |
| | | watchChange(n) { |
| | | this.check() |
| | | }, |
| | | // çå¬v-modeçååï¼éæ°åå§åå
é¨çå¼ |
| | | value(n) { |
| | | if (n !== this.currentValue) { |
| | | this.currentValue = this.format(this.value) |
| | | } |
| | | } |
| | | }, |
| | | computed: { |
| | | getCursorSpacing() { |
| | | // å¤æä¼ å
¥çåä½ï¼å¦æä¸ºpxåä½ï¼éè¦è½¬æpx |
| | | return uni.$u.getPx(this.cursorSpacing) |
| | | }, |
| | | // æé®çæ ·å¼ |
| | | buttonStyle() { |
| | | return (type) => { |
| | | const style = { |
| | | backgroundColor: this.bgColor, |
| | | height: uni.$u.addUnit(this.buttonSize), |
| | | color: this.color |
| | | } |
| | | if (this.isDisabled(type)) { |
| | | style.backgroundColor = '#f7f8fa' |
| | | } |
| | | return style |
| | | } |
| | | }, |
| | | // è¾å
¥æ¡çæ ·å¼ |
| | | inputStyle() { |
| | | const disabled = this.disabled || this.disabledInput |
| | | const style = { |
| | | color: this.color, |
| | | backgroundColor: this.bgColor, |
| | | height: uni.$u.addUnit(this.buttonSize), |
| | | width: uni.$u.addUnit(this.inputWidth) |
| | | } |
| | | return style |
| | | }, |
| | | // ç¨äºçå¬å¤ä¸ªå¼åçåå |
| | | watchChange() { |
| | | return [this.integer, this.decimalLength, this.min, this.max] |
| | | }, |
| | | isDisabled() { |
| | | return (type) => { |
| | | if (type === 'plus') { |
| | | // å¨ç¹å»å¢å æé®æ
åµä¸ï¼å¤ææ´ä½çdisabledï¼æ¯å¦åç¬ç¦ç¨å¢å æé®ï¼ä»¥åå½å弿¯å¦å¤§äºæå¤§çå
è®¸å¼ |
| | | return ( |
| | | this.disabled || |
| | | this.disablePlus || |
| | | this.currentValue >= this.max |
| | | ) |
| | | } |
| | | // ç¹å»åå°æé®åç |
| | | return ( |
| | | this.disabled || |
| | | this.disableMinus || |
| | | this.currentValue <= this.min |
| | | ) |
| | | } |
| | | }, |
| | | }, |
| | | mounted() { |
| | | this.init() |
| | | }, |
| | | methods: { |
| | | init() { |
| | | this.currentValue = this.format(this.value) |
| | | }, |
| | | // æ ¼å¼åæ´çæ°æ®ï¼éå¶èå´ |
| | | format(value) { |
| | | value = this.filter(value) |
| | | // å¦æä¸ºç©ºå符串ï¼é£ä¹è®¾ç½®ä¸º0ï¼åæ¶å°å¼è½¬ä¸ºNumberç±»å |
| | | value = value === '' ? 0 : +value |
| | | // å¯¹æ¯æå¤§æå°å¼ï¼åå¨minåmaxä¹é´çå¼ |
| | | value = Math.max(Math.min(this.max, value), this.min) |
| | | // å¦æè®¾å®äºæå¤§çå°æ°ä½æ°ï¼ä½¿ç¨toFixedå»è¿è¡æ ¼å¼å |
| | | if (this.decimalLength !== null) { |
| | | value = value.toFixed(this.decimalLength) |
| | | } |
| | | return value |
| | | }, |
| | | // è¿æ»¤éæ³çå符 |
| | | filter(value) { |
| | | // åªå
许0-9ä¹é´çæ°åï¼"."ä¸ºå°æ°ç¹ï¼"-"ä¸ºè´æ°æ¶åä½¿ç¨ |
| | | value = String(value).replace(/[^0-9.-]/g, '') |
| | | // 妿åªå
许è¾å
¥æ´æ°ï¼åè¿æ»¤æå°æ°ç¹åçé¨å |
| | | if (this.integer && value.indexOf('.') !== -1) { |
| | | value = value.split('.')[0] |
| | | } |
| | | return value; |
| | | }, |
| | | check() { |
| | | // æ ¼å¼åäºä¹åï¼å¦æååçå¼ä¸ç¸çï¼é£ä¹è®¾ç½®ä¸ºæ ¼å¼ååçå¼ |
| | | const val = this.format(this.currentValue); |
| | | if (val !== this.currentValue) { |
| | | this.currentValue = val |
| | | } |
| | | }, |
| | | // 夿æ¯å¦åºäºç¦æ¢æä½ç¶æ |
| | | // isDisabled(type) { |
| | | // if (type === 'plus') { |
| | | // // å¨ç¹å»å¢å æé®æ
åµä¸ï¼å¤ææ´ä½çdisabledï¼æ¯å¦åç¬ç¦ç¨å¢å æé®ï¼ä»¥åå½å弿¯å¦å¤§äºæå¤§çå
è®¸å¼ |
| | | // return ( |
| | | // this.disabled || |
| | | // this.disablePlus || |
| | | // this.currentValue >= this.max |
| | | // ) |
| | | // } |
| | | // // ç¹å»åå°æé®åç |
| | | // return ( |
| | | // this.disabled || |
| | | // this.disableMinus || |
| | | // this.currentValue <= this.min |
| | | // ) |
| | | // }, |
| | | // è¾å
¥æ¡æ´»å¨ç¦ç¹ |
| | | onFocus(event) { |
| | | this.$emit('focus', { |
| | | ...event.detail, |
| | | name: this.name, |
| | | }) |
| | | }, |
| | | // è¾å
¥æ¡å¤±å»ç¦ç¹ |
| | | onBlur(event) { |
| | | // 对è¾å
¥å¼è¿è¡æ ¼å¼å |
| | | const value = this.format(event.detail.value) |
| | | // ååºbluräºä»¶ |
| | | this.$emit( |
| | | 'blur',{ |
| | | ...event.detail, |
| | | name: this.name, |
| | | } |
| | | ) |
| | | }, |
| | | // è¾å
¥æ¡å¼åçåå |
| | | onInput(e) { |
| | | const { |
| | | value = '' |
| | | } = e.detail || {} |
| | | // 为空è¿å |
| | | if (value === '') return |
| | | let formatted = this.filter(value) |
| | | // æå¤§å
许çå°æ°é¿åº¦ |
| | | if (this.decimalLength !== null && formatted.indexOf('.') !== -1) { |
| | | const pair = formatted.split('.'); |
| | | formatted = `${pair[0]}.${pair[1].slice(0, this.decimalLength)}` |
| | | } |
| | | formatted = this.format(formatted) |
| | | this.emitChange(formatted); |
| | | }, |
| | | // ååºchangeäºä»¶ |
| | | emitChange(value) { |
| | | // 妿å¼å¯äºå¼æ¥åæ´å¼ï¼åä¸ä¿®æ¹å
é¨çå¼ï¼éè¦ç¨æ·æå¨å¨å¤é¨éè¿v-modelåæ´ |
| | | if (!this.asyncChange) { |
| | | this.$nextTick(() => { |
| | | this.$emit('input', value) |
| | | this.currentValue = value |
| | | this.$forceUpdate() |
| | | }) |
| | | } |
| | | this.$emit('change', { |
| | | value, |
| | | name: this.name, |
| | | }); |
| | | }, |
| | | onChange() { |
| | | const { |
| | | type |
| | | } = this |
| | | if (this.isDisabled(type)) { |
| | | return this.$emit('overlimit', type) |
| | | } |
| | | const diff = type === 'minus' ? -this.step : +this.step |
| | | const value = this.format(this.add(+this.currentValue, diff)) |
| | | this.emitChange(value) |
| | | this.$emit(type) |
| | | }, |
| | | // 坹弿©å¤§åè¿è¡åèäºå
¥ï¼åé¤ä»¥æ©å¤§å åï¼é¿å
åºç°æµ®ç¹æ°æä½ç精度é®é¢ |
| | | add(num1, num2) { |
| | | const cardinal = Math.pow(10, 10); |
| | | return Math.round((num1 + num2) * cardinal) / cardinal |
| | | }, |
| | | // ç¹å»å åæé® |
| | | clickHandler(type) { |
| | | this.type = type |
| | | this.onChange() |
| | | }, |
| | | longPressStep() { |
| | | // æ¯é䏿®µæ¶é´ï¼éæ°è°ç¨longPressStepæ¹æ³ï¼å®ç°é¿æå å |
| | | this.clearTimeout() |
| | | this.longPressTimer = setTimeout(() => { |
| | | this.onChange() |
| | | this.longPressStep() |
| | | }, 250); |
| | | }, |
| | | onTouchStart(type) { |
| | | if (!this.longPress) return |
| | | this.clearTimeout() |
| | | this.type = type |
| | | // ä¸å®æ¶é´åï¼é»è®¤è¾¾å°é¿æç¶æ |
| | | this.longPressTimer = setTimeout(() => { |
| | | this.onChange() |
| | | this.longPressStep() |
| | | }, 600) |
| | | }, |
| | | // 触æ¸ç»æï¼æ¸
é¤å®æ¶å¨ï¼åæ¢é¿æå å |
| | | onTouchEnd() { |
| | | if (!this.longPress) return |
| | | this.clearTimeout() |
| | | }, |
| | | // æ¸
é¤å®æ¶å¨ |
| | | clearTimeout() { |
| | | clearTimeout(this.longPressTimer) |
| | | this.longPressTimer = null |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | @import '../../libs/css/components.scss'; |
| | | |
| | | $u-numberBox-hover-bgColor: #E6E6E6 !default; |
| | | $u-numberBox-disabled-color: #c8c9cc !default; |
| | | $u-numberBox-disabled-bgColor: #f7f8fa !default; |
| | | $u-numberBox-plus-radius: 4px !default; |
| | | $u-numberBox-minus-radius: 4px !default; |
| | | $u-numberBox-input-text-align: center !default; |
| | | $u-numberBox-input-font-size: 15px !default; |
| | | $u-numberBox-input-padding: 0 !default; |
| | | $u-numberBox-input-margin: 0 2px !default; |
| | | $u-numberBox-input-disabled-color: #c8c9cc !default; |
| | | $u-numberBox-input-disabled-bgColor: #f2f3f5 !default; |
| | | |
| | | .u-number-box { |
| | | @include flex(row); |
| | | align-items: center; |
| | | |
| | | &__slot { |
| | | /* #ifndef APP-NVUE */ |
| | | touch-action: none; |
| | | /* #endif */ |
| | | } |
| | | |
| | | &__plus, |
| | | &__minus { |
| | | width: 35px; |
| | | @include flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | /* #ifndef APP-NVUE */ |
| | | touch-action: none; |
| | | /* #endif */ |
| | | |
| | | &--hover { |
| | | background-color: $u-numberBox-hover-bgColor !important; |
| | | } |
| | | |
| | | &--disabled { |
| | | color: $u-numberBox-disabled-color; |
| | | background-color: $u-numberBox-disabled-bgColor; |
| | | } |
| | | } |
| | | |
| | | &__plus { |
| | | border-top-right-radius: $u-numberBox-plus-radius; |
| | | border-bottom-right-radius: $u-numberBox-plus-radius; |
| | | } |
| | | |
| | | &__minus { |
| | | border-top-left-radius: $u-numberBox-minus-radius; |
| | | border-bottom-left-radius: $u-numberBox-minus-radius; |
| | | } |
| | | |
| | | &__input { |
| | | position: relative; |
| | | text-align: $u-numberBox-input-text-align; |
| | | font-size: $u-numberBox-input-font-size; |
| | | padding: $u-numberBox-input-padding; |
| | | margin: $u-numberBox-input-margin; |
| | | @include flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | |
| | | &--disabled { |
| | | color: $u-numberBox-input-disabled-color; |
| | | background-color: $u-numberBox-input-disabled-bgColor; |
| | | } |
| | | } |
| | | } |
| | | </style> |