我想实现一个文本掩码input
,它接受一个日期字段。 掩蔽值应直接在内部显示input
。
事情是这样的:
<input type='text' value='____/__/__'>
我写的屏蔽,这个例子的值,但我的目的是让人们写的日期,而无需输入/
或-
分隔月,年和天数。 用户应该能够号进入显示领域,而面罩自动强制格式的用户类型。
我已经看到了在其他网站这种行为,但我不知道它是如何工作或如何实现它自己。
我想实现一个文本掩码input
,它接受一个日期字段。 掩蔽值应直接在内部显示input
。
事情是这样的:
<input type='text' value='____/__/__'>
我写的屏蔽,这个例子的值,但我的目的是让人们写的日期,而无需输入/
或-
分隔月,年和天数。 用户应该能够号进入显示领域,而面罩自动强制格式的用户类型。
我已经看到了在其他网站这种行为,但我不知道它是如何工作或如何实现它自己。
输入掩码可使用的组合来实现keyup
事件,并且HTMLInputElement
value
, selectionStart
,和selectionEnd
属性。 这里是一个非常简单的实现,做一些你想要什么。 这当然不是完美的,但效果很好,足以证明原则:
Array.prototype.forEach.call(document.body.querySelectorAll("*[data-mask]"), applyDataMask); function applyDataMask(field) { var mask = field.dataset.mask.split(''); // For now, this just strips everything that's not a number function stripMask(maskedData) { function isDigit(char) { return /\d/.test(char); } return maskedData.split('').filter(isDigit); } // Replace `_` characters with characters from `data` function applyMask(data) { return mask.map(function(char) { if (char != '_') return char; if (data.length == 0) return char; return data.shift(); }).join('') } function reapplyMask(data) { return applyMask(stripMask(data)); } function changed() { var oldStart = field.selectionStart; var oldEnd = field.selectionEnd; field.value = reapplyMask(field.value); field.selectionStart = oldStart; field.selectionEnd = oldEnd; } field.addEventListener('click', changed) field.addEventListener('keyup', changed) }
ISO Date: <input type="text" value="____-__-__" data-mask="____-__-__"/><br/> Telephone: <input type="text" value="(___) ___-____" data-mask="(___) ___-____"/><br/>
( 中的jsfiddle查看 )
也有许多库在那里它们执行这一功能的。 一些例子包括:
阅读完所有的帖子,我做了我自己的实现之后,我希望能帮助到别人:
我们的想法是,
改进是值得欢迎的。
/** * charCode [48,57] Numbers 0 to 9 * keyCode 46 "delete" * keyCode 9 "tab" * keyCode 13 "enter" * keyCode 116 "F5" * keyCode 8 "backscape" * keyCode 37,38,39,40 Arrows * keyCode 10 (LF) */ function validate_int(myEvento) { if ((myEvento.charCode >= 48 && myEvento.charCode <= 57) || myEvento.keyCode == 9 || myEvento.keyCode == 10 || myEvento.keyCode == 13 || myEvento.keyCode == 8 || myEvento.keyCode == 116 || myEvento.keyCode == 46 || (myEvento.keyCode <= 40 && myEvento.keyCode >= 37)) { dato = true; } else { dato = false; } return dato; } function phone_number_mask() { var myMask = "(___) ___-____"; var myCaja = document.getElementById("phone"); var myText = ""; var myNumbers = []; var myOutPut = "" var theLastPos = 1; myText = myCaja.value; //get numbers for (var i = 0; i < myText.length; i++) { if (!isNaN(myText.charAt(i)) && myText.charAt(i) != " ") { myNumbers.push(myText.charAt(i)); } } //write over mask for (var j = 0; j < myMask.length; j++) { if (myMask.charAt(j) == "_") { //replace "_" by a number if (myNumbers.length == 0) myOutPut = myOutPut + myMask.charAt(j); else { myOutPut = myOutPut + myNumbers.shift(); theLastPos = j + 1; //set caret position } } else { myOutPut = myOutPut + myMask.charAt(j); } } document.getElementById("phone").value = myOutPut; document.getElementById("phone").setSelectionRange(theLastPos, theLastPos); } document.getElementById("phone").onkeypress = validate_int; document.getElementById("phone").onkeyup = phone_number_mask;
<input type="text" name="phone" id="phone" placeholder="(123) 456-7890" required="required" title="eg (123) 456-7890" pattern="^\([0-9]{3}\)\s[0-9]{3}-[0-9]{4}$">
您可以通过使用Java脚本的本地方法也能达到这一点。 它非常简单,并且不需要任何额外的库导入。
<input type="text" name="date" placeholder="yyyy-mm-dd" onkeyup="
var date = this.value;
if (date.match(/^\d{4}$/) !== null) {
this.value = date + '-';
} else if (date.match(/^\d{4}\-\d{2}$/) !== null) {
this.value = date + '-';
}" maxlength="10">
你也可以试试我的实现,键入内容时不必每次按键后的延迟,并有退格键的全力支持和删除。
你可以在线试用: https://jsfiddle.net/qmyo6a1h/1/
<html>
<style>
input{
font-family:'monospace';
}
</style>
<body>
<input type="text" id="phone" placeholder="123-5678-1234" title="123-5678-1234" input-mask="___-____-____">
<input type="button" onClick="showValue_phone()" value="Show Value" />
<input type="text" id="console_phone" />
<script>
function InputMask(element) {
var self = this;
self.element = element;
self.mask = element.attributes["input-mask"].nodeValue;
self.inputBuffer = "";
self.cursorPosition = 0;
self.bufferCursorPosition = 0;
self.dataLength = getDataLength();
function getDataLength() {
var ret = 0;
for (var i = 0; i < self.mask.length; i++) {
if (self.mask.charAt(i) == "_") {
ret++;
}
}
return ret;
}
self.keyEventHandler = function (obj) {
obj.preventDefault();
self.updateBuffer(obj);
self.manageCursor(obj);
self.render();
self.moveCursor();
}
self.updateBufferPosition = function () {
var selectionStart = self.element.selectionStart;
self.bufferCursorPosition = self.displayPosToBufferPos(selectionStart);
console.log("self.bufferCursorPosition==" + self.bufferCursorPosition);
}
self.onClick = function () {
self.updateBufferPosition();
}
self.updateBuffer = function (obj) {
if (obj.keyCode == 8) {
self.inputBuffer = self.inputBuffer.substring(0, self.bufferCursorPosition - 1) + self.inputBuffer.substring(self.bufferCursorPosition);
}
else if (obj.keyCode == 46) {
self.inputBuffer = self.inputBuffer.substring(0, self.bufferCursorPosition) + self.inputBuffer.substring(self.bufferCursorPosition + 1);
}
else if (obj.keyCode >= 37 && obj.keyCode <= 40) {
//do nothing on cursor keys.
}
else {
var selectionStart = self.element.selectionStart;
var bufferCursorPosition = self.displayPosToBufferPos(selectionStart);
self.inputBuffer = self.inputBuffer.substring(0, bufferCursorPosition) + String.fromCharCode(obj.which) + self.inputBuffer.substring(bufferCursorPosition);
if (self.inputBuffer.length > self.dataLength) {
self.inputBuffer = self.inputBuffer.substring(0, self.dataLength);
}
}
}
self.manageCursor = function (obj) {
console.log(obj.keyCode);
if (obj.keyCode == 8) {
self.bufferCursorPosition--;
}
else if (obj.keyCode == 46) {
//do nothing on delete key.
}
else if (obj.keyCode >= 37 && obj.keyCode <= 40) {
if (obj.keyCode == 37) {
self.bufferCursorPosition--;
}
else if (obj.keyCode == 39) {
self.bufferCursorPosition++;
}
}
else {
var bufferCursorPosition = self.displayPosToBufferPos(self.element.selectionStart);
self.bufferCursorPosition = bufferCursorPosition + 1;
}
}
self.setCursorByBuffer = function (bufferCursorPosition) {
var displayCursorPos = self.bufferPosToDisplayPos(bufferCursorPosition);
self.element.setSelectionRange(displayCursorPos, displayCursorPos);
}
self.moveCursor = function () {
self.setCursorByBuffer(self.bufferCursorPosition);
}
self.render = function () {
var bufferCopy = self.inputBuffer;
var ret = {
muskifiedValue: ""
};
var lastChar = 0;
for (var i = 0; i < self.mask.length; i++) {
if (self.mask.charAt(i) == "_" &&
bufferCopy) {
ret.muskifiedValue += bufferCopy.charAt(0);
bufferCopy = bufferCopy.substr(1);
lastChar = i;
}
else {
ret.muskifiedValue += self.mask.charAt(i);
}
}
self.element.value = ret.muskifiedValue;
}
self.preceedingMaskCharCount = function (displayCursorPos) {
var lastCharIndex = 0;
var ret = 0;
for (var i = 0; i < self.element.value.length; i++) {
if (self.element.value.charAt(i) == "_"
|| i > displayCursorPos - 1) {
lastCharIndex = i;
break;
}
}
if (self.mask.charAt(lastCharIndex - 1) != "_") {
var i = lastCharIndex - 1;
while (self.mask.charAt(i) != "_") {
i--;
if (i < 0) break;
ret++;
}
}
return ret;
}
self.leadingMaskCharCount = function (displayIndex) {
var ret = 0;
for (var i = displayIndex; i >= 0; i--) {
if (i >= self.mask.length) {
continue;
}
if (self.mask.charAt(i) != "_") {
ret++;
}
}
return ret;
}
self.bufferPosToDisplayPos = function (bufferIndex) {
var offset = 0;
var indexInBuffer = 0;
for (var i = 0; i < self.mask.length; i++) {
if (indexInBuffer > bufferIndex) {
break;
}
if (self.mask.charAt(i) != "_") {
offset++;
continue;
}
indexInBuffer++;
}
var ret = bufferIndex + offset;
return ret;
}
self.displayPosToBufferPos = function (displayIndex) {
var offset = 0;
var indexInBuffer = 0;
for (var i = 0; i < self.mask.length && i <= displayIndex; i++) {
if (indexInBuffer >= self.inputBuffer.length) {
break;
}
if (self.mask.charAt(i) != "_") {
offset++;
continue;
}
indexInBuffer++;
}
return displayIndex - offset;
}
self.getValue = function () {
return this.inputBuffer;
}
self.element.onkeypress = self.keyEventHandler;
self.element.onclick = self.onClick;
}
function InputMaskManager() {
var self = this;
self.instances = {};
self.add = function (id) {
var elem = document.getElementById(id);
var maskInstance = new InputMask(elem);
self.instances[id] = maskInstance;
}
self.getValue = function (id) {
return self.instances[id].getValue();
}
document.onkeydown = function (obj) {
if (obj.target.attributes["input-mask"]) {
if (obj.keyCode == 8 ||
obj.keyCode == 46 ||
(obj.keyCode >= 37 && obj.keyCode <= 40)) {
if (obj.keyCode == 8 || obj.keyCode == 46) {
obj.preventDefault();
}
//needs to broadcast to all instances here:
var keys = Object.keys(self.instances);
for (var i = 0; i < keys.length; i++) {
if (self.instances[keys[i]].element.id == obj.target.id) {
self.instances[keys[i]].keyEventHandler(obj);
}
}
}
}
}
}
//Initialize an instance of InputMaskManager and
//add masker instances by passing in the DOM ids
//of each HTML counterpart.
var maskMgr = new InputMaskManager();
maskMgr.add("phone");
function showValue_phone() {
//-------------------------------------------------------__Value_Here_____
document.getElementById("console_phone").value = maskMgr.getValue("phone");
}
</script>
</body>
</html>
响应该溶液input
事件,而不是关键事件(如keyup
)会给出一个流畅的体验(没有晃),并更改时没有键盘(上下文菜单,鼠标拖拽,其它设备......)做出同样适用。
下面的代码将寻找既具有输入元件placeholder
属性和data-slots
属性。 后者应限定在被意图/作为输入插槽,例如占位符的字符(多个),“_”。 一个可选的data-accept
属性可设置有一个正则表达式定义的字符被允许在这样的狭槽。 默认为\d
,即数字。
// This code empowers all input tags having a placeholder and data-slots attribute document.addEventListener('DOMContentLoaded', () => { for (const el of document.querySelectorAll("[placeholder][data-slots]")) { const pattern = el.getAttribute("placeholder"), slots = new Set(el.dataset.slots || "_"), prev = (j => Array.from(pattern, (c,i) => slots.has(c)? j=i+1: j))(0), first = [...pattern].findIndex(c => slots.has(c)), accept = new RegExp(el.dataset.accept || "\\d", "g"), clean = input => { input = input.match(accept) || []; return Array.from(pattern, c => input[0] === c || slots.has(c) ? input.shift() || c : c ); }, format = () => { const [i, j] = [el.selectionStart, el.selectionEnd].map(i => { i = clean(el.value.slice(0, i)).findIndex(c => slots.has(c)); return i<0? prev[prev.length-1]: back? prev[i-1] || first: i; }); el.value = clean(el.value).join``; el.setSelectionRange(i, j); back = false; }; let back = false; el.addEventListener("keydown", (e) => back = e.key === "Backspace"); el.addEventListener("input", format); el.addEventListener("focus", format); el.addEventListener("blur", () => el.value === pattern && (el.value="")); } });
[data-slots] { font-family: monospace }
<label>Date time: <input placeholder="dd/mm/yyyy hh:mm" data-slots="dmyh"> </label><br> <label>Telephone: <input placeholder="+1 (___) ___-____" data-slots="_"> </label><br> <label>MAC Address: <input placeholder="XX:XX:XX:XX:XX:XX" data-slots="X" data-accept="[\dA-H]"> </label><br>
Array.prototype.forEach.call(document.body.querySelectorAll("*[data-mask]"), applyDataMask);
function applyDataMask(field) {
var mask = field.dataset.mask.split('');
// For now, this just strips everything that's not a number
function stripMask(maskedData) {
function isDigit(char) {
return /\d/.test(char);
}
return maskedData.split('').filter(isDigit);
}
// Replace `_` characters with characters from `data`
function applyMask(data) {
return mask.map(function(char) {
if (char != '_') return char;
if (data.length == 0) return char;
return data.shift();
}).join('')
}
function reapplyMask(data) {
return applyMask(stripMask(data));
}
function changed() {
var oldStart = field.selectionStart;
var oldEnd = field.selectionEnd;
field.value = reapplyMask(field.value);
field.selectionStart = oldStart;
field.selectionEnd = oldEnd;
}
field.addEventListener('click', changed)
field.addEventListener('keyup', changed)
}
Date: <input type="text" value="__-__-____" data-mask="__-__-____"/><br/>
Telephone: <input type="text" value="(___) ___-____" data-mask="(___) ___-____"/><br/>
下面我介绍我的方法。 我在设置输入事件input
,调用掩蔽()方法,将返回的是一个格式化字符串,我们在插入input
。
HTML:
<input name="phone" pattern="+373 __ ___ ___" class="masked" required>
JQ:在这里我们设置的事件上输入:
$('.masked').on('input', function () {
var input = $(this);
input.val(Masking(input.val(), input.attr('pattern')));
});
JS:功能,这将通过图案格式化串;
function Masking (value, pattern) {
var out = '';
var space = ' ';
var any = '_';
for (var i = 0, j = 0; j < value.length; i++, j++) {
if (value[j] === pattern[i]) {
out += value[j];
}
else if(pattern[i] === any && value[j] !== space) {
out += value[j];
}
else if(pattern[i] === space && value[j] !== space) {
out += space;
j--;
}
else if(pattern[i] !== any && pattern[i] !== space) {
out += pattern[i];
j--;
}
}
return out;
}
使用此代码: -
<input type="text" placeholder="" data-mask="9999/99/99">
与添加这个脚本https://github.com/RobinHerbots/Inputmask