N3-components/N3-components

View on GitHub
src/InputNumber/n3InputNumber.vue

Summary

Maintainability
Test Coverage
<template>
<div :class="classObj" :style="{width: width}">
  <div :class="`${prefixCls}-input-number-handler-wrap`">
    <a unselectable="unselectable"
      ref="up"
      @click="_up"
      @mouse.down="preventDefault"
      :class="[prefixCls + '-input-number-handler',prefixCls + '-input-number-handler-up',upDisabledClass]">
        <n3-icon
          :class="`${prefixCls}-input-number-handler-up-inner`" 
          type="angle-up" 
          @click="preventDefault" 
          unselectable="unselectable">
        </n3-icon>
    </a>
    <a unselectable="unselectable"
       ref="down"
       @mouse.down="preventDefault"
       @click="_down"
       :class="[prefixCls + '-input-number-handler', prefixCls + '-input-number-handler-down', downDisabledClass]">
       <n3-icon
          :class="`${prefixCls}-input-number-handler-down-inner`" 
          type="angle-down" 
          @click="preventDefault" 
          unselectable="unselectable">
        </n3-icon>
    </a>
  </div>
  <div :class="prefixCls + '-input-number-input-wrap'">
    <n3-input
      type="number"
      @focus="_onFocus"
      :width="width"
      :rules="rules" 
      :placeholder="placeholder"
      :custom-validate="customValidate"
      @blur="_onBlur"
      @keydown.native.stop="_onKeyDown"
      @change="_onChange"
      :readonly="readonly"
      :disabled="disabled"
      :name="name"
      :value="currentValue">
    </n3-input> 
  </div>
</div>
</template>

<script>
import n3Input from '../Input/n3Input'
import n3Icon from '../Icon/n3Icon'
import inputMixin from '../Mixin/inputMixin'

function isValueNumber (value) {
  return !isNaN(Number(value))
}

function calNum (num1, num2, symb) {
  let sq1, sq2, m
  try {
    sq1 = num1.toString().split('.')[1].length
  } catch (e) {
    sq1 = 0
  }
  try {
    sq2 = num2.toString().split('.')[1].length
  } catch (e) {
    sq2 = 0
  }
  m = Math.pow(10, Math.max(sq1, sq2))
  
  if (symb === '+') {
    return (num1 * m + num2 * m) / m
  } else if (symb === '-') {
    return (num1 * m - num2 * m) / m
  }
}

function preventDefault (e) {
  e.preventDefault()
}

export default {
  name: 'n3InputNumber',
  mixins: [inputMixin],
  props: {
    prefixCls: {
      type: String,
      default: 'n3'
    },
    max: {
      type: Number
    },
    min: {
      type: Number
    },
    value: {
      type: [Number, String]
    },
    step: {
      type: Number,
      default: 1
    },
    onChange: {
      type: Function
    }
  },

  data () {
    let value = this.value
    if (value < this.min) {
      this.$emit('input', this.min)
      value = this.min
    }
    if (value > this.max) {
      this.$emit('input', this.max)
      value = this.max
    }

    return {
      noop: () => {},
      preventDefault: preventDefault,
      upDisabledClass: '',
      downDisabledClass: '',
      currentValue: value
    }
  },

  components: {
    n3Input,
    n3Icon
  },

  computed: {
    classObj () {
      let {prefixCls, disabled, readonly} = this
      let klass = {}

      klass[prefixCls + '-input-number'] = true
      klass[prefixCls + '-input-number-disabled'] = disabled
      klass[prefixCls + '-input-number-readonly'] = readonly

      return klass
    }

  },

  watch: {
    currentValue (val) {
      if (this.inner) {
        this.inner = false
        return
      }
      this.inner = true
      this.$emit('input', val)
    },
    value (val) {
      if (this.inner) {
        this.inner = false
        return
      }
      this.inner = true
      if (isValueNumber(val)) {
        val = Number(val)
        if (val >= this.max) {
          this.upDisabledClass = `${this.prefixCls}-input-number-handler-up-disabled`
        } else if (val <= this.min) {
          this.downDisabledClass = `${this.prefixCls}-input-number-handler-down-disabled`
        } else {
          this.upDisabledClass = ''
          this.downDisabledClass = ''
        }
        this.currentValue = val
      } else {
        this.upDisabledClass = `${this.prefixCls}-input-number-handler-up-disabled`
        this.downDisabledClass = `${this.prefixCls}-input-number-handler-down-disabled`
      }
    }
  },

  methods: {
    _setValue (value) {
      this.currentValue = value
      this.$emit('input', value)
      this.$emit('change', value)
    },

    _onChange (value) {
      let val = String(value).trim()

      if (!val) {
        this._setValue(val)
      } else if (isValueNumber(val)) {
        val = Number(val)
        if (val < this.min) return
        if (val > this.max) return
        this._setValue(val)
      } else if (val === '-') {
        if (this.min >= 0) return
        this.currentValue = val
      }
    },

    _onKeyDown (e) {
      if (e.keyCode === 38) {
        this._up(e)
      } else if (e.keyCode === 40) {
        this._down(e)
      }
    },

    _onFocus () {
      this.$emit('focus')
    },

    _onBlur () {
      if (this.value === '-') {
        this._setValue('')
      }
      this.$emit('blur')
    },

    _step (type, e) {
      if (this.disabled || this.readonly) return

      let value = Number(this.value)
      const stepNum = Number(this.step)

      if (isNaN(value)) return
      if (type === 'down') value = calNum(value, stepNum, '-')
      else if (type === 'up') value = calNum(value, stepNum, '+')

      if (value > this.max || value < this.min) return

      this._setValue(value)
    },

    _down (e) {
      if (this.downDisabledClass) {
        return
      }
      this._step('down', e)
    },

    _up (e) {
      if (this.upDisabledClass) {
        return
      }
      this._step('up', e)
    }
  }
}

</script>