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-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
,当它触发时完成以下操作:
- 记录触发时间
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 实现
原创声明: 该文章为原创文章,转载请注明出处。