InputNumer 组件的难点在于:基于 Input 组件进行二次拓展的 InputNumber 组件
- 实现鼠标长按,计数器数值变动;
- 导致 InputNumber 组件的值变化,有以下操作v-model绑定值的变化,加、减按钮,input组件的输入,需要对上述结果进行处理,所以如何设计合理模式,减少冗余代码。
1. 实例
代码
<!-- 基础用法 -->
<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 UI-Library
2. 原理
首先利用 Input 组件,在其 slot prepend
和 slot append
两个插槽内,插入相应的加、减按钮,具体如下。
<fat-inputclass="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
,当它触发时完成以下操作:
- 记录触发时间
startTime
; - 定义一个
setInterval
,每隔一个period
就调用相应的timerHandler
函数,来模拟长按操作; - 在
document
上监听mouseup
事件,当鼠标还原时触发。
然后,当鼠标还原时,就会触发 document
的 mouseup
事件,此时相应的处理为:
- 记录触发时间为
endTime
,如果满足endTime - startTime < period
条件,则执行一次timerHandler
; - 利用
clearInterval
停止setInterval
,之后移除对mouseup
的监听。
由于每次修改 InputNumber 组件的值时,都需判断是否超出最大、最小值、或是输入的值是否为数字等规则,即使将这些规则抽象为一个函数,也会显得代码有些臃肿,所以选用 computed
属性对 inputValue
状态进行一层代理,具体如下
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
的修改,同时劫持 get
,set
函数,在 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" />
复制代码
往期文章:
- 从零实现Vue的组件库(零)- 基本结构以及构建工具
- 从零实现Vue的组件库(一)- Toast 实现
- 从零实现Vue的组件库(二)- Slider 实现
- 从零实现Vue的组件库(三)- Tabs 实现
- 从零实现Vue的组件库(四)- File-Reader 实现
- 从零实现Vue的组件库(五)- Breadcrumb 实现
- 从零实现Vue的组件库(六)- Hover-Tip 实现
- 从零实现Vue的组件库(七)- Message-Box 实现
- 从零实现Vue的组件库(八)- Input 实现
- 从零实现Vue的组件库(九)- InputNumber 实现
- 从零实现Vue的组件库(十)- Select 实现
- 从零实现Vue的组件库(十一)- Date-picker 实现
- 从零实现Vue的组件库(十二)- Table 实现
- 从零实现Vue的组件库(十三)- Pagination 实现
- 从零实现Vue的组件库(十四)- RadioGroup 实现
- 从零实现Vue的组件库(十五)- CheckboxGroup 实现
原创声明: 该文章为原创文章,转载请注明出处。