Element InputNumber 計數(shù)器的實(shí)現(xiàn)示例
前言
這篇我們繼續(xù)研究InputNumber。
基本實(shí)現(xiàn)
基本的準(zhǔn)備工作過后,開始基本實(shí)現(xiàn)。
上測試代碼:
<el-input-number v-model="num" @change="handleChange" :min="1" :max="10" label="描述文字"> </el-input-number>
上組件代碼:
<template>
<div
:class="[
'el-input-number',
]"
>
<span
class="el-input-number__decrease"
role="button"
:class="{'is-disabled': minDisabled}"
@click="decrease"
>
<i class="el-icon-minus"></i>
</span>
<span
class="el-input-number__increase"
role="button"
:class="{'is-disabled': maxDisabled}"
@click="increase"
>
<i class="el-icon-plus"></i>
</span>
<el-input
ref="input"
:value="value"
@input="value => $emit('input', value)"
>
</el-input>
</div>
</template>
<script>
import ElInput from '../Input/index'
export default {
name: 'ElInputNumber',
props: {
value: {},
max: {
type: Number,
default: Infinity
},
min: {
type: Number,
default: -Infinity
},
},
computed: {
minDisabled() {
return this.value - 1 < this.min;
},
maxDisabled() {
return this.value + 1 > this.max;
},
},
methods: {
decrease() {
if(this.minDisabled) return
this.$emit('input', this.value - 1)
},
increase() {
if(this.maxDisabled) return
this.$emit('input', this.value + 1)
}
},
components: {
ElInput
}
}
</script>
上效果:

這次可以復(fù)用Input組件,兩邊加新增/減少兩個按鈕,實(shí)現(xiàn)加減邏輯。再控制最大值最小值的時候,禁用按鈕,基本實(shí)現(xiàn)完成。
點(diǎn)擊按鈕持續(xù)增加/減少
現(xiàn)在添加:點(diǎn)擊加減按鈕的時候,不抬起鼠標(biāo),值就會持續(xù)增加/減少的特性。
要實(shí)現(xiàn)此功能,源碼中用到了directive自定義指令,靠節(jié)流mousedown事件來實(shí)現(xiàn)持續(xù)點(diǎn)擊效果。
寫自定義命令:
import { once, on } from '../utils/dom';
export default {
bind(el, binding, vnode) {
let interval = null;
let startTime;
// binding.expression 就是decrease/increase 事件名稱
// handler就是對應(yīng)的相應(yīng)函數(shù)
const handler = () => vnode.context[binding.expression].apply();
const clear = () => {
if (Date.now() - startTime < 100) {
handler();
}
clearInterval(interval);
interval = null;
};
on(el, 'mousedown', (e) => {
if (e.button !== 0) return;
startTime = Date.now();
once(document, 'mouseup', clear);
clearInterval(interval);
// 實(shí)現(xiàn)節(jié)流
interval = setInterval(handler, 100);
});
}
};
在組件中使用自定義命令:
import RepeatClick from '../../directives/repeat-click';
directives: {
repeatClick: RepeatClick
},
<span
class="el-input-number__decrease"
role="button"
:class="{'is-disabled': minDisabled}"
v-repeat-click="decrease"
>
<i class="el-icon-minus"></i>
</span>
<span
class="el-input-number__increase"
role="button"
:class="{'is-disabled': maxDisabled}"
v-repeat-click="increase"
>
<i class="el-icon-plus"></i>
</span>
禁用狀態(tài)
- 添加 { 'is-disabled': disabled } 到根節(jié)點(diǎn)樣式上。
- 添加:disabled="disabled"到el-input節(jié)點(diǎn)上。
- 添加if(this.disabled) return 到decrease/increase方法上。
完成效果:

步數(shù)
上測試代碼:
<el-input-number v-model="num" :step="2"></el-input-number>
給組件添加step屬性。在組件中把+/-1這樣到代碼替換為+/- this.step。
嚴(yán)格步數(shù)
step-strictly屬性接受一個Boolean。如果這個屬性被設(shè)置為true,則只能輸入步數(shù)的倍數(shù)。
上測試代碼:
<el-input-number v-model="num" :step="2" step-strictly></el-input-number>
要想實(shí)現(xiàn)嚴(yán)格步數(shù),我們直接輸入的值,會檢查是不是step的倍數(shù),如果不是,則換成step的倍數(shù)。這就不能直接把InputNumber的value直接綁定在內(nèi)部的el-input上了。先在el-input的input事件記錄輸入的值。再在change事件中將值賦予給value,最后在watch.value上校驗(yàn)輸入的值,并轉(zhuǎn)換成step的倍數(shù)。
data() {
return {
currentValue: 0, // 緩存上次輸入的值
userInput: null, // 緩存當(dāng)前輸入的值
};
},
<el-input
ref="input"
:disabled="disabled"
:value="currentValue" // 變?yōu)榻壎╟urrentValue
@input="handleInput"
@change="handleInputChange"
>
</el-input>
// 先在el-input的input事件記錄輸入的值
handleInput(value) {
this.userInput = value;
},
// 在change事件中將值賦予給value
handleInputChange(value) {
let newVal = value === '' ? undefined : Number(value);
if (!isNaN(newVal) || value === '') {
this.setCurrentValue(newVal);
}
this.userInput = null;
},
setCurrentValue(newVal) {
const oldVal = this.currentValue;
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;
},
watch: {
// 在watch.value上校驗(yàn)輸入的值,并轉(zhuǎn)換成step的倍數(shù)
value: {
immediate: true,
handler(value) {
let newVal = value === undefined ? value : Number(value);
// 設(shè)置嚴(yán)格步數(shù)的邏輯
if (this.stepStrictly) {
newVal = Math.round(newVal / this.step) * this.step
}
if (newVal >= this.max) newVal = this.max;
if (newVal <= this.min) newVal = this.min;
this.currentValue = newVal;
this.userInput = null;
this.$emit('input', newVal);
}
}
},
精度
上測試代碼:
<el-input-number v-model="numPrecision" :precision="2" :step="0.1" :max="10"></el-input-number>
這里step變成小數(shù)了,那在累加得過程中,就會有0.1+0.2這樣得精度問題出現(xiàn)了。element的解決思路是將值擴(kuò)大精度倍進(jìn)行計算,得到結(jié)果后再除以精度倍數(shù)。
increase() {
if(this.maxDisabled || this.disabled) return
const value = this.value || 0;
const newVal = this._increase(value, this.step);
this.setCurrentValue(newVal);
},
_increase(val, step) {
if (typeof val !== 'number' && val !== undefined) return this.currentValue;
// step是0.1,precisionFactor是10。
const precisionFactor = Math.pow(10, this.numPrecision);
return this.toPrecision((precisionFactor * val + precisionFactor * step) / precisionFactor);
},
// 確保計算得結(jié)果0.10000000001這種誤差情況會被消除
toPrecision(num, precision) {
if (precision === undefined) precision = this.numPrecision;
return parseFloat(Math.round(num * Math.pow(10, precision)) / Math.pow(10, precision));
},
在展示的時候,利用toFixed函數(shù)展示精度即可。
效果如下:

尺寸
添加size屬性,在根元素得樣式添加size ? 'el-input-number--' + size : ''。
效果如下:

按鈕位置
設(shè)置 controls-position 屬性可以控制按鈕位置。
上測試代碼:
<el-input-number v-model="num" controls-position="right" @change="handleChange" :min="1" :max="10"> </el-input-number>
通過controls-position='right',在組件內(nèi)控制樣式即可。
效果如下:

總結(jié)
嚴(yán)格步數(shù)和精度這兩個特性得邏輯稍有些復(fù)雜,需要多研究一會。
源碼在碼云: https://gitee.com/DaBuChen/my-element-ui/tree/input-number
到此這篇關(guān)于Element InputNumber 計數(shù)器的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)Element InputNumber 計數(shù)器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue使用element-plus依賴實(shí)現(xiàn)表格增加的示例代碼
這篇文章主要為大家詳細(xì)介紹了vue使用element-plus依賴實(shí)現(xiàn)表格增加,文中示例代碼講解的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2023-12-12
Vue 菜單欄點(diǎn)擊切換單個class(高亮)的方法
今天小編就為大家分享一篇Vue 菜單欄點(diǎn)擊切換單個class(高亮)的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-08-08
Vue3 Pinia獲取全局狀態(tài)變量的實(shí)現(xiàn)方式
這篇文章主要介紹了Vue3 Pinia獲取全局狀態(tài)變量的實(shí)現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05
解決vue2使用腳手架配置prettier報錯prettier/prettier:context.getPhysical
這篇文章主要介紹了解決vue2使用腳手架配置prettier報錯prettier/prettier:context.getPhysicalFilename is not a function問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-03-03
如何使用Gitee Pages服務(wù) 搭建Vue項(xiàng)目
這篇文章主要介紹了如何使用Gitee Pages服務(wù) 搭建Vue項(xiàng)目,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-10-10

