首页 > 其他 > 详细

计时器组件的封装对比

时间:2020-11-25 09:46:26      阅读:31      评论:0      收藏:0      [点我收藏+]

参考UI组件库:

1.elmentUI:https://github.com/ElemeFE/element/tree/master

2.antd;https://github.com/vueComponent/ant-design-vue/

3.Iview;https://github.com/view-design/ViewUI

使用demo:iView和antd的API基本一致

https://codepen.io/share-web/pen/NWRKGOX

https://www.iviewui.com/components/input-number

el-inputNumber:

<template>
<!-- @dragstart.prevent:拖拽开始就阻止自身的默认事件 -->
  <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>
    <!-- 输入回调:鼠标事件+键盘事件:
        新需求:对displayValue的符号进行过滤替换显示
     -->
    <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
    },
    props: {
      step: {
        type: Number,
        default: 1
      },
      stepStrictly: {
        type: Boolean,
        default: false
      },
      max: {
        type: Number,
        default: Infinity
      },
      min: {
        type: Number,
        default: -Infinity
      },
      value: {},
      disabled: Boolean,
      size: String,
      controls: {
        type: Boolean,
        default: true
      },
      controlsPosition: {
        type: String,
        default: ‘‘
      },
      name: String,
      label: String,
      placeholder: String,
      precision: {
        type: Number,
        validator(val) {
          return val >= 0 && val === parseInt(val, 10);
        }
      }
    },
    data() {
      return {
        currentValue: 0,
        userInput: null
      };
    },
    watch: {
      value: {
        immediate: true,
        handler(value) {
          let newVal = value === undefined ? value : Number(value);
          if (newVal !== undefined) {
            if (isNaN(newVal)) {
              return;
            }

            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) {
          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(Math.round(num * Math.pow(10, precision)) / Math.pow(10, 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;

        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>

a-input-number:jsx语法

InputNumber:iView计数器

<template>
    <div :class="wrapClasses">
        <!-- 图标 -->
        <div :class="handlerClasses">
            <a
                @click="up"
                :class="upClasses">
                <span :class="innerUpClasses" @click="preventDefault"></span>
            </a>
            <a
                @click="down"
                :class="downClasses">
                <span :class="innerDownClasses" @click="preventDefault"></span>
            </a>
        </div>
        <!-- 输入框 -->
        <div :class="inputWrapClasses">
            <input
                :id="elementId"
                :class="inputClasses"
                :disabled="itemDisabled"
                autocomplete="off"
                spellcheck="false"
                :autofocus="autofocus"
                @focus="focus"
                @blur="blur"
                @keydown.stop="keyDown"
                @input="change"
                @mouseup="preventDefault"
                @change="change"
                :readonly="readonly || !editable"
                :name="name"
                :value="formatterValue"
                :placeholder="placeholder">
        </div>
    </div>
</template>
<script>
    import { oneOf, findComponentUpward } from ../../utils/assist;
    import Emitter from ../../mixins/emitter;
    import mixinsForm from ../../mixins/form;
    const prefixCls = ivu-input-number;
    const iconPrefixCls = ivu-icon;
    function addNum (num1, num2) {
        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;
        }
//        if (sq1 === 0 || sq2 === 0) {
//            return num1 + num2;
//        } else {
//            m = Math.pow(10, Math.max(sq1, sq2));
//            return (num1 * m + num2 * m) / m;
//        }
        m = Math.pow(10, Math.max(sq1, sq2));
        return (Math.round(num1 * m) + Math.round(num2 * m)) / m;
    }
    export default {
        name: InputNumber,
        mixins: [ Emitter, mixinsForm ],
        props: {
            max: {
                type: Number,
                default: Infinity
            },
            min: {
                type: Number,
                default: -Infinity
            },
            step: {
                type: Number,
                default: 1
            },
            activeChange: {
                type: Boolean,
                default: true
            },
            value: {
                type: Number,
                default: 1
            },
            size: {
                validator (value) {
                    return oneOf(value, [small, large, default]);
                },
                default () {
                    return !this.$IVIEW || this.$IVIEW.size === ‘‘ ? default : this.$IVIEW.size;
                }
            },
            disabled: {
                type: Boolean,
                default: false
            },
            autofocus: {
                type: Boolean,
                default: false
            },
            readonly: {
                type: Boolean,
                default: false
            },
            editable: {
                type: Boolean,
                default: true
            },
            name: {
                type: String
            },
            precision: {
                type: Number
            },
            elementId: {
                type: String
            },
            formatter: {
                type: Function
            },
            parser: {
                type: Function
            },
            placeholder: {
                type: String,
                default: ‘‘
            },
        },
        data () {
            return {
                focused: false,
                upDisabled: false,
                downDisabled: false,
                currentValue: this.value
            };
        },
        computed: {
            wrapClasses () {
                return [
                    `${prefixCls}`,
                    {
                        [`${prefixCls}-${this.size}`]: !!this.size,
                        [`${prefixCls}-disabled`]: this.itemDisabled,
                        [`${prefixCls}-focused`]: this.focused
                    }
                ];
            },
            handlerClasses () {
                return `${prefixCls}-handler-wrap`;
            },
            upClasses () {
                return [
                    `${prefixCls}-handler`,
                    `${prefixCls}-handler-up`,
                    {
                        [`${prefixCls}-handler-up-disabled`]: this.upDisabled
                    }
                ];
            },
            innerUpClasses () {
                return `${prefixCls}-handler-up-inner ${iconPrefixCls} ${iconPrefixCls}-ios-arrow-up`;
            },
            downClasses () {
                return [
                    `${prefixCls}-handler`,
                    `${prefixCls}-handler-down`,
                    {
                        [`${prefixCls}-handler-down-disabled`]: this.downDisabled
                    }
                ];
            },
            innerDownClasses () {
                return `${prefixCls}-handler-down-inner ${iconPrefixCls} ${iconPrefixCls}-ios-arrow-down`;
            },
            inputWrapClasses () {
                return `${prefixCls}-input-wrap`;
            },
            inputClasses () {
                return `${prefixCls}-input`;
            },
            precisionValue () {
                // can not display 1.0
                if(!this.currentValue) return this.currentValue;
                return this.precision ? this.currentValue.toFixed(this.precision) : this.currentValue;
            },
            formatterValue () {
                if (this.formatter && this.precisionValue !== null) {
                    return this.formatter(this.precisionValue);
                } else {
                    return this.precisionValue;
                }
            }
        },
        methods: {
            preventDefault (e) {
                e.preventDefault();
            },
            up (e) {
                const targetVal = Number(e.target.value);
                if (this.upDisabled && isNaN(targetVal)) {
                    return false;
                }
                this.changeStep(up, e);
            },
            down (e) {
                const targetVal = Number(e.target.value);
                if (this.downDisabled && isNaN(targetVal)) {
                    return false;
                }
                this.changeStep(down, e);
            },
            changeStep (type, e) {
                if (this.itemDisabled || this.readonly) {
                    return false;
                }
                const targetVal = Number(e.target.value);
                let val = Number(this.currentValue);
                const step = Number(this.step);
                if (isNaN(val)) {
                    return false;
                }
                // input a number, and key up or down
                if (!isNaN(targetVal)) {
                    if (type === up) {
                        if (addNum(targetVal, step) <= this.max) {
                            val = targetVal;
                        } else {
                            return false;
                        }
                    } else if (type === down) {
                        if (addNum(targetVal, -step) >= this.min) {
                            val = targetVal;
                        } else {
                            return false;
                        }
                    }
                }
                if (type === up) {
                    val = addNum(val, step);
                } else if (type === down) {
                    val = addNum(val, -step);
                }
                this.setValue(val);
            },
            setValue (val) {
                // 如果 step 是小数,且没有设置 precision,是有问题的
                if (val && !isNaN(this.precision)) val = Number(Number(val).toFixed(this.precision));
                const {min, max} = this;
                if (val!==null) {
                    if (val > max) {
                        val = max;
                    } else if (val < min) {
                        val = min;
                    }
                }
                this.$nextTick(() => {
                    this.currentValue = val;
                    this.$emit(input, val);
                    this.$emit(on-change, val);
                    this.dispatch(FormItem, on-form-change, val);
                });
            },
            focus (event) {
                this.focused = true;
                this.$emit(on-focus, event);
            },
            blur () {
                this.focused = false;
                this.$emit(on-blur);
                if (!findComponentUpward(this, [DatePicker, TimePicker, Cascader, Search])) {
                    this.dispatch(FormItem, on-form-blur, this.currentValue);
                }
            },
            keyDown (e) {
                if (e.keyCode === 38) {
                    e.preventDefault();
                    this.up(e);
                } else if (e.keyCode === 40) {
                    e.preventDefault();
                    this.down(e);
                }
            },
            change (event) {
                if (event.type == change && this.activeChange) return;
                if (event.type == input && !this.activeChange) return;
                let val = event.target.value.trim();
                if (this.parser) {
                    val = this.parser(val);
                }
                const isEmptyString = val.length === 0;
                if(isEmptyString){
                    this.setValue(null);
                    return;
                }
                if (event.type == input && val.match(/^\-?\.?$|\.$/)) return; // prevent fire early if decimal. If no more input the change event will fire later
                val = Number(val);
                if (!isNaN(val)) {
                    this.currentValue = val;
                    this.setValue(val);
                } else {
                    event.target.value = this.currentValue;
                }
            },
            changeVal (val) {
                val = Number(val);
                if (!isNaN(val)) {
                    const step = this.step;
                    this.upDisabled = val + step > this.max;
                    this.downDisabled = val - step < this.min;
                } else {
                    this.upDisabled = true;
                    this.downDisabled = true;
                }
            }
        },
        mounted () {
            this.changeVal(this.currentValue);
        },
        watch: {
            value (val) {
                this.currentValue = val;
            },
            currentValue (val) {
                this.changeVal(val);
            },
            min () {
                this.changeVal(this.currentValue);
            },
            max () {
                this.changeVal(this.currentValue);
            }
        }
    };
</script>

-待续-

 

计时器组件的封装对比

原文:https://www.cnblogs.com/wheatCatcher/p/14033707.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!