美文网首页Element非官方分析
Element分析(组件篇)—— InputNumber

Element分析(组件篇)—— InputNumber

作者: liril | 来源:发表于2017-01-02 00:10 被阅读5360次

    input-number组件是用来输入数字的,也不是很复杂。

    最外层

    最外层是一个div.el-input-number,上面有一些动态的class

    <div class="el-input-number"
      :class="[
        size ? 'el-input-number--' + size : '',
        { 'is-disabled': disabled },
        { 'is-without-controls': !controls}
      ]"
    >
    </div>
    

    size

    size是一个prop,用来控制其大小的。

    props: {
      size: String,
    }
    

    disabled

    disabled也是prop,用来控制是否禁用。

    props: {
      disabled: Boolean,
    }
    

    controls

    controls也是prop,用来控制是否有控制器。

    props: {
      controls: {
        type: Boolean,
        default: true
      }
    }
    

    减少按钮

    减少按钮是一个span

    <span
      v-if="controls"
      class="el-input-number__decrease el-icon-minus"
      :class="{'is-disabled': minDisabled}"
      v-repeat-click="decrease"
    >
    </span>
    

    minDisabled

    minDisabled是一个计算属性,用来控制是否禁用该按钮。

    computed: {
      minDisabled() {
        return this.accSub(this.value, this.step) < this.min;
      },
    }
    

    v-repeat-click

    v-repeat-click是一个指令,用来控制左键按下时不断触发事件。

    directives: {
      repeatClick: {
        bind(el, binding, vnode) {
          let interval = null;  // 定时器
          let startTime;
    
          const handler = () => vnode.context[binding.expression]();  // 获取表达式的内容
    
          const clear = () => {
            // 如果当前时间距离开始时间少于 100ms,执行 handler
            if (new Date() - startTime < 100) {
              handler();
            }
            // 清除计时器
            clearInterval(interval);
            interval = null;
          };
    
          // 绑定鼠标点击下的事件
          on(el, 'mousedown', () => {
            startTime = new Date();  // 更新当前时间
            once(document, 'mouseup', clear);  // 给鼠标抬起绑定一次性事件 clear
            interval = setInterval(handler, 100);  // 开始定时器
          });
        }
      }
    },
    

    decrease

    控制数值减少。

    methods: {
      decrease() {
        if (this.minDisabled) return;  // 如果减少按钮不可以用,直接返回
        const value = this.value || 0;  // 默认为0
        if (this.accSub(value, this.step) < this.min || this.disabled) return;  // 如果减少后小于最小值,或者当前input不可用都直接返回
        this.currentValue = this.accSub(value, this.step);  // 否则设置新的值
      },
    }
    

    其中accSub是另一个用来做减法的方法,用来处理小数的精度问题。

    methods: {
      // arg1 当前值
      // arg2 步进值
      accSub(arg1, arg2) {
        var r1, r2, m, n;
        try {
          r1 = arg1.toString().split('.')[1].length;  // 处理当前值小数的位数
        } catch (e) {
          r1 = 0;
        }
        try {
          r2 = arg2.toString().split('.')[1].length;  // 处理步进值小数的位数
        } catch (e) {
          r2 = 0;
        }
        m = Math.pow(10, Math.max(r1, r2));  // 为了转换成整数,好处理精度问题
        n = (r1 >= r2) ? r1 : r2;  // 精度取较大值
        return parseFloat(((arg1 * m - arg2 * m) / m).toFixed(n));
      },
    }
    

    增加按钮

    增加按钮也是一个span,绝大多数逻辑和减少按钮一样,只是减法变成加法,在此不再进行赘述。

    el-input

    最后是内嵌了一个el-input来实现输入框,并且进行了处理可以将input-number的具名slotappendprepend传入el-input中,这样可以更好地复用。

    <el-input
      v-model.number="currentValue"
      @keydown.up.native="increase"
      @keydown.down.native="decrease"
      @blur="handleBlur"
      :disabled="disabled"
      :size="size"
      ref="input"
    >
        <template slot="prepend" v-if="$slots.prepend">
          <slot name="prepend"></slot>
        </template>
        <template slot="append" v-if="$slots.append">
          <slot name="append"></slot>
        </template> 
    </el-input>
    

    这里只有handleBlur没有解释过,它会设置el-input的值。

    methods: {
      handleBlur() {
        this.$refs.input.setCurrentValue(this.currentValue);
      }
    }
    

    其他

    data

    初始化的时候,修正value

    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 {
        currentValue: value
      };
    },
    

    watch

    watch: {
    value(val) {
    this.currentValue = val; // value改变的时候,currentValue也改变
    },

    currentValue(newVal, oldVal) {
    if (newVal <= this.max && newVal >= this.min) { // 新值合法
    this.$emit('change', newVal, oldVal); // 触发 change 事件
    this.$emit('input', newVal); // 触发 input 事件
    } else { // 不合法就回复
    this.currentValue = oldVal;
    }
    }
    },

    相关文章

      网友评论

      本文标题:Element分析(组件篇)—— InputNumber

      本文链接:https://www.haomeiwen.com/subject/nhoivttx.html