123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- import baseComponent from '../helpers/baseComponent'
- import classNames from '../helpers/classNames'
- const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || Math.pow(2, 53) - 1
- const toNumberWhenUserInput = (num) => {
- if (/\.\d*0$/.test(num) || num.length > 16) {
- return num
- }
- if (isNaN(num)) {
- return num
- }
- return Number(num)
- }
- const getValidValue = (value, min, max) => {
- let val = parseFloat(value)
- if (isNaN(val)) {
- return value
- }
- if (val < min) {
- val = min
- }
- if (val > max) {
- val = max
- }
- return val
- }
- baseComponent({
- externalClasses: ['wux-sub-class', 'wux-input-class', 'wux-add-class'],
- properties: {
- prefixCls: {
- type: String,
- value: 'wux-input-number',
- },
- shape: {
- type: String,
- value: 'square',
- },
- min: {
- type: Number,
- value: -MAX_SAFE_INTEGER,
- },
- max: {
- type: Number,
- value: MAX_SAFE_INTEGER,
- },
- step: {
- type: Number,
- value: 1,
- },
- defaultValue: {
- type: Number,
- value: 0,
- },
- value: {
- type: Number,
- value: 0,
- observer(newVal) {
- if (this.data.controlled) {
- this.updated(newVal)
- }
- },
- },
- disabled: {
- type: Boolean,
- value: true,
- },
- longpress: {
- type: Boolean,
- value: false,
- },
- color: {
- type: String,
- value: 'balanced',
- },
- controlled: {
- type: Boolean,
- value: false,
- },
- },
- data: {
- inputValue: 0,
- disabledMin: false,
- disabledMax: false,
- },
- computed: {
- classes() {
- const { prefixCls, shape, color, disabledMin, disabledMax } = this.data
- const wrap = classNames(prefixCls, {
- [`${prefixCls}--${shape}`]: shape,
- })
- const sub = classNames(`${prefixCls}__selector`, {
- [`${prefixCls}__selector--sub`]: true,
- [`${prefixCls}__selector--${color}`]: color,
- [`${prefixCls}__selector--disabled`]: disabledMin,
- })
- const add = classNames(`${prefixCls}__selector`, {
- [`${prefixCls}__selector--add`]: true,
- [`${prefixCls}__selector--${color}`]: color,
- [`${prefixCls}__selector--disabled`]: disabledMax,
- })
- const icon = `${prefixCls}__icon`
- const input = `${prefixCls}__input`
- return {
- wrap,
- sub,
- add,
- icon,
- input,
- }
- },
- },
- methods: {
- /**
- * 更新值
- */
- updated(value, condition = true, trigger = false) {
- const { min, max } = this.data
- const inputValue = getValidValue(value, min, max)
- const disabledMin = inputValue <= min
- const disabledMax = inputValue >= max
- // 更新数值,判断最小或最大值禁用 sub 或 add 按钮
- if (condition) {
- this.setData({
- inputValue,
- disabledMin,
- disabledMax,
- })
- }
- // 触发事件
- if (trigger) {
- this.triggerEvent('change', { value: inputValue })
- }
- },
- /**
- * 数字计算函数
- */
- calculation(type, meta) {
- const { disabledMax, disabledMin, inputValue, step, longpress, controlled } = this.data
- // add
- if (type === 'add') {
- if (disabledMax) return false
- this.updated(inputValue + step, !controlled, true)
- }
- // sub
- if (type === 'sub') {
- if (disabledMin) return false
- this.updated(inputValue - step, !controlled, true)
- }
- // longpress
- if (longpress && meta) {
- this.timeout = setTimeout(() => this.calculation(type, meta), 100)
- }
- },
- /**
- * 当键盘输入时,触发 input 事件
- */
- onInput(e) {
- this.clearInputTimer()
- this.inputTime = setTimeout(() => {
- const value = toNumberWhenUserInput(e.detail.value)
- this.updated(value, !this.data.controlled)
- this.triggerEvent('change', { value })
- }, 300)
- },
- /**
- * 输入框聚焦时触发
- */
- onFocus(e) {
- this.triggerEvent('focus', e.detail)
- },
- /**
- * 输入框失去焦点时触发
- */
- onBlur(e) {
- // always set input value same as value
- this.setData({
- inputValue: this.data.inputValue,
- })
- this.triggerEvent('blur', e.detail)
- },
- /**
- * 手指触摸后,超过350ms再离开
- */
- onLongpress(e) {
- const { type } = e.currentTarget.dataset
- const { longpress } = this.data
- if (longpress) {
- this.calculation(type, true)
- }
- },
- /**
- * 手指触摸后马上离开
- */
- onTap(e) {
- const { type } = e.currentTarget.dataset
- const { longpress } = this.data
- if (!longpress || longpress && !this.timeout) {
- this.calculation(type, false)
- }
- },
- /**
- * 手指触摸动作结束
- */
- onTouchEnd() {
- this.clearTimer()
- },
- /**
- * 手指触摸动作被打断,如来电提醒,弹窗
- */
- onTouchCancel() {
- this.clearTimer()
- },
- /**
- * 清除长按的定时器
- */
- clearTimer() {
- if (this.timeout) {
- clearTimeout(this.timeout)
- this.timeout = null
- }
- },
- /**
- * 清除输入框的定时器
- */
- clearInputTimer() {
- if (this.inputTime) {
- clearTimeout(this.inputTime)
- this.inputTime = null
- }
- },
- },
- attached() {
- const { defaultValue, value, controlled } = this.data
- const inputValue = controlled ? value : defaultValue
- this.updated(inputValue)
- },
- detached() {
- this.clearTimer()
- this.clearInputTimer()
- },
- })
|