InputNumber 實現

基於 Input 組件進行二次拓展的 InputNumber 組件html

InputNumer 組件的難點在於:
  • 實現鼠標長按,計數器數值變更;
  • 致使 InputNumber 組件的值變化,有如下操做v-model綁定值的變化,加、減按鈕,input組件的輸入,須要對上述結果進行處理,因此如何設計合理模式,減小冗餘代碼。

1. 實例

最終效果

代碼git

<!-- 基礎用法 -->
<fat-radio-group v-model="value">
    <fat-radio :value="1">備選項</fat-radio>
    <fat-radio :value="2">備選項</fat-radio>
</fat-radio-group>
<!-- 禁用狀態 -->
<fat-radio-group v-model="anotherValue">
    <fat-radio :value="1">備選項</fat-radio>
        <fat-radio :value="2" disabled>備選項</fat-radio>
</fat-radio-group>
<!-- 步數 -->
<fat-input-number :step="5" v-model="stepValue" />
<!-- 最大,最小值限制 -->
<fat-input-number :max="20" :min="0" :step="5" v-model="value" />
複製代碼

實例地址:InputNumber 實例github

代碼地址:Github UI-Librarybash

2. 原理

首先利用 Input 組件,在其 slot prependslot append 兩個插槽內,插入相應的加、減按鈕,具體以下。app

<fat-input
    class="input-number-inner"
    type="text"
    :disabled="disabled"
    v-model="inputValue"
    v-bind="$attrs"
>
    <template slot="prepend">
        <div
            :class="['prepend-part', { 'is-disabled': addDisabled }]"
            @mousedown.stop="!addDisabled && handleClick('add')"
        >
            <fat-icon name="add" size="16"/>
        </div>
    </template>

    <template slot="append">
        <div
            :class="['append-part', { 'is-disabled': decDisabled }]"
            @mousedown.stop="!decDisabled && handleClick('dec')"
        >
            <fat-icon name="remove" size="16"/>
        </div>
    </template>
</fat-input>
複製代碼

接下來實現加、減按鈕的長按功能,其本質就是將 click 事件分爲了,mousedown 以及 mouseup 兩個事件來處理,具體體如今 handleClick 函數。函數

handleClick(type) {
    const { step } = this;
    const period = 100;
    const timerHandler = () => {
        const { addDisabled, decDisabled } = this;
        if (!addDisabled && type === "add") this.inputNumberValue += step;
        if (!decDisabled && type === "dec") this.inputNumberValue -= step;
    };
    const timer = setInterval(timerHandler, period);
    const startTime = new Date();

    const handler = () => {
        const endTime = new Date();
        
        if (endTime - startTime < period) timerHandler();
        clearInterval(timer);
        document.removeEventListener("mouseup", handler, false);
    };
    document.addEventListener("mouseup", handler, false);
}
複製代碼

首先,監聽按鈕的 mousedown ,當它觸發時完成如下操做:ui

  • 記錄觸發時間startTime;
  • 定義一個 setInterval,每隔一個 period 就調用相應的 timerHandler 函數,來模擬長按操做;
  • document 上監聽 mouseup 事件,當鼠標還原時觸發。

而後,當鼠標還原時,就會觸發 documentmouseup 事件,此時相應的處理爲:this

  • 記錄觸發時間爲 endTime,若是知足 endTime - startTime < period 條件,則執行一次 timerHandler
  • 利用 clearInterval 中止 setInterval,以後移除對 mouseup 的監聽。

因爲每次修改 InputNumber 組件的值時,都需判斷是否超出最大、最小值、或是輸入的值是否爲數字等規則,即便將這些規則抽象爲一個函數,也會顯得代碼有些臃腫,因此選用 computed 屬性對 inputValue 狀態進行一層代理,具體以下spa

computed: {
    inputNumberValue: {
        get() {
            return this.inputValue;
        },
        set(value) {
            const { min, max, inputValue } = this;
            const limits = [{
                need: value => !isNum(value),
                value: inputValue
            }, {
                need: value => value >= max,
                value: max
            }, {
                need: value => value <= min,
                value: min
            }, {
                need: () => true,
                value: value
            }];
            this.inputValue = limits.find(limit => limit.need(value)).value;
        }
    }
}
複製代碼

將對 inputValue 的修改,轉變爲對 inputNumberValue 的修改,同時劫持 getset 函數,在 set 中,定義規則。設計

3. 使用

實現了基礎的InputNumber,後續能夠在自行在樣式上進行擴展。

<!-- 基礎用法 -->
<fat-input-number v-model="value" />
<!-- 禁用狀態 -->
<fat-input-number disabled />
<!-- 步數 -->
<fat-input-number :step="5" v-model="stepValue" />
<!-- 最大,最小值限制 -->
<fat-input-number :max="20" :min="0" :step="5" v-model="value" />
複製代碼

原創聲明: 該文章爲原創文章,轉載請註明出處。

相關文章
相關標籤/搜索