element input-number source

input-number.vue

<template>
  <div
    @dragstart.prevent
    :class="[
      'el-input-number',
      inputNumberSize ? 'el-input-number--' + inputNumberSize : '',
      { 'is-disabled': inputNumberDisabled },
      { 'is-without-controls': !controls },
      { 'is-controls-right': controlsAtRight }
    ]">
    <span
      class="el-input-number__decrease"
      role="button"
      v-if="controls"
      v-repeat-click="decrease"
      :class="{'is-disabled': minDisabled}"
      @keydown.enter="decrease">
      <i :class="`el-icon-${controlsAtRight ? 'arrow-down' : 'minus'}`"></i>
    </span>
    <span
      class="el-input-number__increase"
      role="button"
      v-if="controls"
      v-repeat-click="increase"
      :class="{'is-disabled': maxDisabled}"
      @keydown.enter="increase">
      <i :class="`el-icon-${controlsAtRight ? 'arrow-up' : 'plus'}`"></i>
    </span>
    <el-input
      ref="input"
      :value="displayValue"
      :placeholder="placeholder"
      :disabled="inputNumberDisabled"
      :size="inputNumberSize"
      :max="max"
      :min="min"
      :name="name"
      :label="label"
      @keydown.up.native.prevent="increase"
      @keydown.down.native.prevent="decrease"
      @blur="handleBlur"
      @focus="handleFocus"
      @input="handleInput"
      @change="handleInputChange">
    </el-input>
  </div>
</template>
<script>
  import ElInput from 'element-ui/packages/input';
  import Focus from 'element-ui/src/mixins/focus'; import RepeatClick from 'element-ui/src/directives/repeat-click'; export default { name: 'ElInputNumber', mixins: [Focus('input')], inject: { elForm: { default: '' }, elFormItem: { default: '' }}, Directives: {repeatClick: RepeatClick}, Components: ElInput {}, The props: {// step counter step: {type: Number The, default : . 1 }, // if only the input a multiple step stepStrictly : {type: Boolean, default : to false }, // set the maximum allowed counter max: {type: Number the, default : Infinity}, // set the minimum allowed value counter min: {type: Number the, default : - Infinity }, // value / v-model binding value value: {}, // whether the counter is disabled disabled: Boolean, // counter Large size String, Small size: String, // whether the control button controls: {type: Boolean , default : to true }, // right control button position String controlsPosition: {type: String, default: '' }, // native property name: String, // label text input box associated label: String, // default input box placeholder placeholder: String, // numerical precision precision: {type: Number, validator (val) return { Val > = 0 && Val === the parseInt (Val, 10 );}}}, Data () {return {currentValue: 0 , userInput: null };}, Watch: {// vaue value variation value: { // trigger an immediate load immediate: to true , // custom function Handler (value) {the let newVal = value === undefined ? value: Number The (value); IF (newVal ==! undefined) { if (isNaN(newVal)) { return; } // 是否只能输入 step 的倍数 if (this.stepStrictly) { const stepPrecision = this.getPrecision(this.step); const precisionFactor = Math.pow(10, stepPrecision); newVal = Math.round(newVal / this.step) * precisionFactor * this.step / precisionFactor; } if (this.precision !== undefined) { newVal = this.toPrecision(newVal, this.precision); } } if (newVal >= this.max) newVal = this.max; if (newVal <= this.min) newVal = this.min; this.currentValue = newVal; this.userInput = null; this.$emit('input', newVal); } } }, computed: { // 不能小于最小数  minDisabled() { return this._decrease(this.value, this.step) < this.min; }, // 不能大于最大数  maxDisabled() { return this._increase(this.value, this.step) > this.max; }, numPrecision() { const { value, step, getPrecision, precision } = this; const stepPrecision = getPrecision(step); if (precision !== undefined) { if (stepPrecision > precision) { console.warn('[Element Warn][InputNumber]precision should not be less than the decimal places of step'); } return precision; } else { return Math.max(getPrecision(value), stepPrecision); } }, // 控制条在右侧  controlsAtRight() { return this.controls && this.controlsPosition === 'right'; }, _elFormItemSize() { return (this.elFormItem || {}).elFormItemSize; }, inputNumberSize() { return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size; }, inputNumberDisabled() { return this.disabled || (this.elForm || {}).disabled; }, displayValue() { if (this.userInput !== null) { return this.userInput; } let currentValue = this.currentValue; if (typeof currentValue === 'number') { // 如果只能输入 step 的倍数 if (this.stepStrictly) { // 小数点后面几位小数  const stepPrecision = this.getPrecision(this.step); const precisionFactor = Math.pow(10, stepPrecision); currentValue = Math.round(currentValue / this.step) * precisionFactor * this.step / precisionFactor; } if (this.precision !== undefined) { currentValue = currentValue.toFixed(this.precision); } } return currentValue; } }, methods: { // 截取为传入的位数  toPrecision(num, precision) { if (precision === undefined) precision = this.numPrecision; return parseFloat(Number(num).toFixed(precision)); }, // 获取小数点后面还有几位  getPrecision(value) { if (value === undefined) return 0; const valueString = value.toString(); const dotPosition = valueString.indexOf('.'); let precision = 0; if (dotPosition !== -1) { precision = valueString.length - dotPosition - 1; } return precision; }, _increase(val, step) { if (typeof val !== 'number' && val !== undefined) return this.currentValue; const precisionFactor = Math.pow(10, this.numPrecision); // Solve the accuracy problem of JS decimal calculation by converting the value to integer. return this.toPrecision((precisionFactor * val + precisionFactor * step) / precisionFactor); }, // 递减函数  _decrease(val, step) { if (typeof val !== 'number' && val !== undefined) return this.currentValue; // eg: 10的0.1次方  const precisionFactor = Math.pow(10, this.numPrecision); return this.toPrecision((precisionFactor * val - precisionFactor * step) / precisionFactor); }, increase() { if (this.inputNumberDisabled || this.maxDisabled) return; const value = this.value || 0; const newVal = this._increase(value, this.step); this.setCurrentValue(newVal); }, decrease() { if (this.inputNumberDisabled || this.minDisabled) return; const value = this.value || 0; const newVal = this._decrease(value, this.step); this.setCurrentValue(newVal); }, handleBlur(event) { this.$emit('blur', event); }, handleFocus(event) { this.$emit('focus', event); }, setCurrentValue(newVal) { const oldVal = this.currentValue; if (typeof newVal === 'number' && this.precision !== undefined) { newVal = this.toPrecision(newVal, this.precision); } if (newVal >= this.max) newVal = this.max; if (newVal <= this.min) newVal = this.min; if (oldVal === newVal) return; this.userInput = null; this.$emit('input', newVal); this.$emit('change', newVal, oldVal); this.currentValue = newVal; }, handleInput(value) { this.userInput = value; }, handleInputChange(value) { const newVal = value === '' ? undefined : Number(value); if (!isNaN(newVal) || value === '') { this.setCurrentValue(newVal); } this.userInput = null; }, select() { this.$refs.input.select(); } }, mounted() { let innerInput = this.$refs.input.$refs.input; innerInput.setAttribute('role', 'spinbutton'); innerInput.setAttribute('aria-valuemax', this.max); innerInput.setAttribute('aria-valuemin', this.min); innerInput.setAttribute('aria-valuenow', this.currentValue); innerInput.setAttribute('aria-disabled', this.inputNumberDisabled); }, updated() { if (!this.$refs || !this.$refs.input) return; const innerInput = this.$refs.input.$refs.input; innerInput.setAttribute('aria-valuenow', this.currentValue); } }; </script>
repeat-click.js

 

Import {Once, ON} from 'Element-UI / the src / utils / DOM' ; 

Export default { 
  the bind (EL, Binding, the vnode) { 
    the let interval The = null ; 
    the let the startTime; 
    / * * 
     * context is a Component type data structure, this component is the flow defined structure, specifically to see the contents of vue source of flow, 
     * component is a component, so the context is the context in which the components vnode is located, look binding.expression, the official website that this is the 
     * v - repeat - decrease method click = "decrease" in this method written in the assembly methods, 
     * then the context [binding.expression] is context [ 'decrease'] thus to get a Decrease in the method of assembly, 
     * similar this.decrease as used in the appliance, and then finally the apply () 
    is very strange, apply usage it is the first parameter represents the target object to be executed, if null or undefined, said this method is invoked on the window, there is no argument,
    That is undefined, it is executed on a window 
     *    
    const Handler* / = () => vnode.context [binding.expression] .apply (); 
    const Clear = () => {
       IF (Date.now () - the startTime <100 ) { 
        Handler (); 
      } 
      the clearInterval (interval the); 
      interval the = null ; 
    }; 

    ON (EL, 'mouseDown', (E) => {
       / *  
        this method is bound to an element event, if-else processing compatibility case, attachEvent ie is the method, addEventListener method is the other major browsers. 
         oN the third parameter is the event handler, on the first sentence if (e.button! == 0) return is the e.button press the mouse which key 
        Element source code analysis series 7-InputNumber (digital input box) 
        not equal to 0 is a press the left button is not, because generally only deal with left-click event, attention onclick respond only to press the left mouse button, and onmousedown 
        the response by pressing three keys, so here to distinguish.


        on the last sentence interval = setInterval (handler, 100) set the timer handler execution method in order to increase or decrease the numbers once every 0.1s trigger event, 
        then we think, press down the mouse to add dom element events: timed execution handler then when the mouse is lifted sure to destroy the timer, otherwise it will trigger an infinite handler method, 
        resulting figure has increased or decreased, so once (document, 'mouseup', clear) this sentence is destroyed when the mouse is lifted timer, look clear method 
        which is destroyed clearInterval timer, if the foregoing logic is critical, a recording time, when the mouse, the mouse is lifted detects the current time - the time when the press 
         <100 ms, if so triggering a click, if you do not write this if, you can not achieve click, because if you do not write, because the interval = setInterval (handler, 100) , 
         at 100 milliseconds after pressing will trigger a click, then within 100 milliseconds when lifting the mouse interval has been clear. Finally, note that at Once (the Document, 'mouseUp', the Clear), 
          Once is only triggered once the higher-order functions 
      * / 
      IF (e.button == 0!) Return ; 
      startTime = Date.now (); 
      Once (the Document,'mouseup', clear);
      clearInterval(interval);
      interval = setInterval(handler, 100);
    });
  }
};

 

Guess you like

Origin www.cnblogs.com/wsk1576025821/p/10954835.html