Element InputNumber 計(jì)數(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)行計(jì)算,得到結(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); }, // 確保計(jì)算得結(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 計(jì)數(shù)器的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)Element InputNumber 計(jì)數(shù)器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue使用element-plus依賴實(shí)現(xiàn)表格增加的示例代碼
這篇文章主要為大家詳細(xì)介紹了vue使用element-plus依賴實(shí)現(xiàn)表格增加,文中示例代碼講解的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2023-12-12Vue 菜單欄點(diǎn)擊切換單個class(高亮)的方法
今天小編就為大家分享一篇Vue 菜單欄點(diǎn)擊切換單個class(高亮)的方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-08-08Vue3 Pinia獲取全局狀態(tài)變量的實(shí)現(xiàn)方式
這篇文章主要介紹了Vue3 Pinia獲取全局狀態(tài)變量的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05解決vue2使用腳手架配置prettier報(bào)錯prettier/prettier:context.getPhysical
這篇文章主要介紹了解決vue2使用腳手架配置prettier報(bào)錯prettier/prettier:context.getPhysicalFilename is not a function問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-03-03如何使用Gitee Pages服務(wù) 搭建Vue項(xiàng)目
這篇文章主要介紹了如何使用Gitee Pages服務(wù) 搭建Vue項(xiàng)目,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-10-10