我們經(jīng)常會要求用戶在文本框中輸入特定的數(shù)據(jù),或者輸入特定格式的數(shù)據(jù).例如,必須包含木屑字符,或者必須匹配某種模式.由于文本框在默認(rèn)情況下沒有提供多少驗(yàn)證數(shù)據(jù)的手段,因此必須是喲個(gè)JavaScript來完成此類過濾輸入的操作.而綜合運(yùn)用事件和DOM手段,就可以將普通的文本框轉(zhuǎn)換成能夠理解用戶輸入數(shù)據(jù)的工程型控件.
1.原生事件方法:
- input事件操作el.value值
此處按照事件的順序均可實(shí)現(xiàn)
<!--onkeydown-->
<input onkeydown="this.value=this.value.replace(/\D/g,'')">
<!--onkeypress-->
<input onkeypress="this.value=this.value.replace(/\D/g,'')">
<!--推薦-->
<!--onkeyup-->
<input onkeyup="this.value=this.value.replace(/\D/g,'')">
onkeydown
,onkeypress
都有一個(gè)比較明顯的缺點(diǎn),就是非數(shù)組字符仍可以輸入,只是在下一次輸入之后才會替換掉.
keyup
事件能在輸入不正確的字符之后立刻就能清除掉, 但是這個(gè)動(dòng)作還是人眼可見的.
封裝 : 此種方式也可先定義一個(gè)函數(shù),將this
傳遞到該函數(shù)然后進(jìn)行復(fù)雜操作
<input onkeyup="keyUp(this)">
<script>
function keyUp(el) {
el.value = el.value.replace(/\D/g, '');
}
</script>
- 最佳方案
event.preventDefault
為了讓不希望輸入的字符不會在input框中閃現(xiàn),可以通過阻止某個(gè)按鍵的默認(rèn)行為來屏蔽此類字符.在極端的情況下,可以通過下列代碼屏蔽所有按鍵操作.
EventUtil.addHandler(textBox,"keypress",function(event){
event=EventUtil.getEvent(event);
EventUtil.preventDefault(event);
})
放上用到的EventUtil
公共方法
let EventUtil = {
addHandler: function (element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + type, hander);
} else {
element["on" + type] = handler;
}
},
removeHandler: function (element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else if (element.detachEvent) {
element.detachEvent("on" + type, handler);
} else {
element["on" + type] = null;
}
},
getEvent: function (event) {
return event ? event : window.event;
},
getTarget: function (event) {
return event.target || event.srcElement;
},
preventDefault: function (event) {
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
},
stopPropagation: function (event) {
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true;
}
},
getCharCode: function (event) {
if (typeof event.charCode === "number") {
return event.charCode;
} else {
return event.keyCode;
}
},
getClipboardText: function (event) {
var clipboardData = (event.clipboardData || window.clipboardData);
return clipboardData.getData("text");
},
setClipboardText: function (event, value) {
if (event.clipboardData) {
return event.clipboardData.setData("text/plain", value);
} else if (window.clipboardData) {
return window.clipboardData.setData("text", value);
}
}
}
運(yùn)行以上代碼后,由于所有按鍵操作都被屏蔽,結(jié)果會導(dǎo)致文本框變成只讀的.如果只想屏蔽特定的字符,則需要檢測keypress事件對應(yīng)的字符編碼,然后再?zèng)Q定如何響應(yīng).例如,下列代碼只允許用戶輸入數(shù)值.
<input type="text" id="textBox">
<script>
EventUtil.addHandler(textBox, "keypress", function (event) {
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
var charCode = EventUtil.getCharCode(event);
if (!/\d/.test(String.fromCharCode(charCode)) && charCode>9 && !event.ctrlKey) {
EventUtil.preventDefault(event);
}
})
</script>
例子中,使用EventUtil.getCharCode()實(shí)現(xiàn)了跨瀏覽器取得字符編碼,然后使用String.fromCharCode()將字符編碼轉(zhuǎn)換成字符串,再使用正則表達(dá)式/\d/來測試該字符串,將測試失敗的數(shù)值使用EventUtil.preventDefault()屏蔽按鍵事件.
- vue指令方式
通過vue指令可以在input 標(biāo)簽上添加相應(yīng)指令名稱就可以達(dá)到操作原生input事件,滿足各種input功能需求, 邏輯即清晰亦是解耦,可移植性強(qiáng).
- 限制input輸入數(shù)字最大最小值
下面是我封裝后的完整示例:
HTML部分
<div id="app">
<h2>input 控制輸入</h2>
<div>
<input type="number" v-model.lazy="value" v-int-num="{cb:showAlert,min:10,max:100,decimal:0}" >
</div>
</div>
JavaScript部分
// 截取精確小數(shù)方法
const round = (n, decimals = 0) => Number(`${Math.round(`${n}e${decimals}`)}e-${decimals}`);
Vue.directive('int-num', {
bind: function (el, binding, vnode) {
let {
cb,//回調(diào)函數(shù),可在不滿足條件的情況下做一下后續(xù)提示等操作
min,//最小值
max,//最大值
decimal //精確小數(shù)位數(shù)
} = binding.value ? binding.value : {
cb: Function,
min: 0,
max: 100,
decimal: 0
};
if (min > max) {
throw new Error("最小值不能大于最大值");
return;
}
el.keypressHandler = function (event) {
// 當(dāng)小數(shù)位數(shù)位0時(shí),此時(shí)不允許輸入'.'點(diǎn)符號
if (decimal === 0 && event.charCode === 46) {
event.preventDefault();//組織默認(rèn)行為
event.stopPropagation();//停止傳遞冒泡事件,不會進(jìn)入input事件中
}
}
el.inputHandler = function (event) {
if (isNaN(Number(el.value))) {
el.value = "";
} else {
el.value = round(Number(el.value), decimal);
}
cb.call(null, Number(el.value));
if (el.value > max) {
el.value = max;
}
}
el.blurHandler = function () {
if (el.value > max) {
cb.call(this, "最大值是 " + max)
}
if (el.value < min) {
cb.call(this, "最小值是 " + min);
}
}
// 添加事件監(jiān)聽
el.addEventListener("keypress", el.keypressHandler)
el.addEventListener('input', el.inputHandler);
el.addEventListener("blur", el.blurHandler);
},
unbind: function (el) {
// 移除事件監(jiān)聽
el.removeEventListener("keypress", el.keypressHandler)
el.removeEventListener('input', el.inputHandler);
el.removeEventListener("blur", el.blurHandler);
}
});
new Vue({
el: "#app",
data: {
value: ""
},
methods: {
showAlert(e) {
console.info(JSON.stringify(e));
}
}
})
特別注意:
v-model
值綁定的時(shí)候需要使用.lazy
進(jìn)行修飾,因?yàn)?code>v-model內(nèi)部也是用input
事件截取值和綁定值的渗蟹,哪個(gè)先執(zhí)行是不確定的芹彬,偶爾會看到input值閃動(dòng)出現(xiàn)减江。當(dāng)用.lazy
修飾之后速缨,v-model
內(nèi)部使用change
事件綁定值尤慰,而change事件是在input事件之后关斜,故此時(shí)已經(jīng)是經(jīng)過自定義處理之后的值叽粹,不會出現(xiàn)數(shù)值跳動(dòng)的情況炭菌。
其實(shí)內(nèi)部實(shí)現(xiàn)也是input事件的原生方法,經(jīng)過vue指令的封裝,控制輸入行為會更靈活,也更直觀和方便.
如果需要對特定字符進(jìn)行組織或只允許輸入特定字符,可以在keypress事件中用 event.charCode
判斷即可實(shí)現(xiàn).
題外話:
為了只允許輸入數(shù)字可以用input[type=number]和input[type=tel],但是有一些缺陷
- input[type=number]
不支持maxlength罪佳,支持輸入e
,.
- input[type=tel]
在移動(dòng)設(shè)備上,input[type=tel] 是支持maxlength的黑低,而且只能輸入數(shù)字鍵盤赘艳。支持輸入#
,*
,+