標籤:直接 type ide lin val none href efi const
在Vue中的項目,基於VUX-UI開發,一個常見的需求:
1、金額輸入框2、彈出數字鍵台3、僅支援輸入兩位小數,限制最大11位元,不允許0開頭
第一,首先想到額就是在VUX-UI中制定type=number。--不可行
VUX中的文檔和代碼說明,type=number不支援maxLength,會報錯,而且沒有正則替換的處理或者鉤子函數,只有輸入後提示校正資訊。
第二,基於VUX中XInput封裝,有如下問題
1)兩層v-model,正則替換的值不會觸發input框渲染
解決:currentValue賦值為foramttedValue,放入setTimeout(func ,0)中,讓input框先渲染為正則替換前的值,再渲染為替換後的值
currentValue(val, oldVal) { // 調用filter過濾資料 let formattedValue = this.filter(val); if (this.type === ‘number‘) { formattedValue = this.typeNumberFilter(formattedValue, oldVal); } if (val !== formattedValue || val === ‘‘) { setTimeout(() => { this.currentValue = formattedValue; }, 0); } this.$emit(‘input‘, formattedValue); },
View Code
2)數字鍵台input type=number,會導致maxlength失效,無法限制長度
解決:用slice(0, max)處理
if (formattedValue.length > this.max) { formattedValue = formattedValue.slice(0, this.max); }
View Code
3)數字鍵台input type=number ,連續輸入小數點...導致實際值和顯示值不一致
解決:用原生的 inputElement.value = oldValue處理
const inputEle = this.$children[0].$refs.input; // TODO: 待大範圍驗證:處理連續輸入..後,type=number的input框會把值修改為‘‘的問題;fastclick導致type=number報錯 // 問題描述: 1.00. 不會觸發值改變,1.00.不會觸發值改變,1.00.【\d\.】都會把值修改為空白字串‘‘。hack處理的條件說明如下: // 1、當校正後是空值,(因input=number,formattedValue為‘‘表明 原始newVal也為‘‘) // 2、輸入框拿到的是空值(因input=number導致輸入框立即被賦予空值。點擊清除按鈕時,這裡input輸入框還是上次的值) // 3、上次輸入大於兩位(避免最後一位無法刪除的問題。最後一位刪除時,oldVal.length === 1) if (formattedValue === ‘‘ && inputEle.value === ‘‘ && oldVal && oldVal.match(/^(\d)[\d.]+/)) { formattedValue = oldVal; } setTimeout(() => { inputEle.value = formattedValue; }, 0);
View Code
4)IOS中數字鍵台有%$*等特殊字元
解決:用原生的 inputElement.onkeydown監聽事件,非數字和退格和小數點直接return事件
mounted() { if (this.type === ‘number‘) { const inputEle = this.$refs.xinput.$refs.input; // eslint-disable-next-line inputEle.onkeydown = (e) => { const keyCode = e.keyCode; if (!this.isBackspace(keyCode) && !this.isDot(keyCode) && !this.isNumber(keyCode)) { // 其他按鍵 e.preventDefault(); e.stopPropagation(); return false; } }; } }
View Code
第三,其他說明
為什麼不用 type=tel?
type=tel在ios中沒有小數點
第四,全部代碼
<template> <XInput :title="title" :max="currentMax" :min="currentMin" :type="type" v-model="currentValue" @on-focus="onFoucus()" @on-blur="onBlur()" :show-clear="showClear" :placeholder="placeholder" ref="xinput"> <template v-if="$slots.label" slot="label"><slot name="label"></slot></template> <template v-if="$slots.right" slot="right"><slot name="right"></slot></template> </XInput></template><script>export default { data() { return { currentValue: this.value, }; }, computed: { currentMax() { return (this.type === ‘number‘) ? undefined : this.max; }, currentMin() { return (this.type === ‘number‘) ? undefined : this.min; } }, props: { title: String, max: Number, min: Number, type: String, showClear: { type: Boolean, default: true, }, placeholder: String, value: [String, Number], filter: { type: Function, default: (value) => { let formattedValue = ‘‘; const match = value.match(/^([1-9]\d*(\.[\d]{0,2})?|0(\.[\d]{0,2})?)[\d.]*/); if (match) { formattedValue = match[1]; } return formattedValue; }, } }, watch: { currentValue(val, oldVal) { // 調用filter過濾資料 let formattedValue = this.filter(val); if (this.type === ‘number‘) { formattedValue = this.typeNumberFilter(formattedValue, oldVal); } if (val !== formattedValue || val === ‘‘) { setTimeout(() => { this.currentValue = formattedValue; }, 0); } this.$emit(‘input‘, formattedValue); }, value(value) { this.currentValue = value; }, }, methods: { onFoucus() { this.$emit(‘on-focus‘); }, onBlur() { this.$emit(‘on-blur‘); }, typeNumberFilter(val, oldVal) { const inputEle = this.$refs.xinput.$refs.input; let formattedValue = val; // 由於type=number不支援maxLength,用slice類比 if (formattedValue.length > this.max) { formattedValue = formattedValue.slice(0, this.max); } // TODO: 待大範圍驗證:處理連續輸入..後,type=number的input框會把值修改為‘‘的問題;fastclick導致type=number報錯 // 問題描述: 1.00. 不會觸發值改變,1.00.不會觸發值改變,1.00.【\d\.】都會把值修改為空白字串‘‘。hack處理的條件說明如下: // 1、當校正後是空值,(因input=number,formattedValue為‘‘表明 原始newVal也為‘‘) // 2、輸入框拿到的是空值(因input=number導致輸入框立即被賦予空值。點擊清除按鈕時,這裡input輸入框還是上次的值) // 3、上次輸入大於兩位(避免最後一位無法刪除的問題。最後一位刪除時,oldVal.length === 1) if (formattedValue === ‘‘ && inputEle.value === ‘‘ && oldVal && oldVal.match(/^(\d)[\d.]+/)) { formattedValue = oldVal; } setTimeout(() => { inputEle.value = formattedValue; }, 0); return formattedValue; }, isBackspace(keyCode) { return keyCode === 8; }, isDot(keyCode) { return keyCode === 46 || keyCode === 110 || keyCode === 190; }, isNumber(keyCode) { return (keyCode >= 48 && keyCode <= 57) || (keyCode >= 96 && keyCode <= 105); }, }, mounted() { if (this.type === ‘number‘) { const inputEle = this.$refs.xinput.$refs.input; // eslint-disable-next-line inputEle.onkeydown = (e) => { const keyCode = e.keyCode; if (!this.isBackspace(keyCode) && !this.isDot(keyCode) && !this.isNumber(keyCode)) { // 其他按鍵 e.preventDefault(); e.stopPropagation(); return false; } }; } }};</script>
View Code
【筆記】移動端H5數字鍵台input type=number的處理(IOS和Android)