我想为接受日期的文本input
字段实现掩码。掩码值应直接显示在input
。
这样的事情:
<input type='text' value='____/__/__'>
我在此示例中将掩码编写为值,但我的目的是允许人们在不键入/
或-
的情况下编写日期以分隔月,年和日。用户应该能够在显示的字段中输入数字,而掩码会在用户输入时自动强制执行格式。
我在其他网站上看到过这种行为,但我不知道它是如何工作的,或者我自己如何实现它。
答案 0 :(得分:35)
输入掩码可以使用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)
}
&#13;
ISO Date: <input type="text" value="____-__-__" data-mask="____-__-__"/><br/>
Telephone: <input type="text" value="(___) ___-____" data-mask="(___) ___-____"/><br/>
&#13;
还有许多库可以执行此功能。一些例子包括:
答案 1 :(得分:19)
阅读完所有帖子后,我做了自己的实施,希望对某人有所帮助:
这个想法是,
欢迎改进。
/**
* 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;
&#13;
<input type="text" name="phone" id="phone" placeholder="(123) 456-7890" required="required" title="e.g (123) 456-7890" pattern="^\([0-9]{3}\)\s[0-9]{3}-[0-9]{4}$">
&#13;
答案 2 :(得分:10)
您也可以使用JavaScripts的本机方法实现此目的。它很简单,不需要任何额外的库来导入。
<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">
答案 3 :(得分:4)
您也可以尝试我的实施,在每次按键输入内容后都没有延迟,并且完全支持退格和删除。
您可以在线试用: 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>
答案 4 :(得分:1)
一种响应eval()
事件而不是按键事件(例如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 }
答案 5 :(得分:0)
前一段时间我写了一个类似的解决方案。
当然,这只是一个PoC,可以进一步改进。
此解决方案涵盖以下功能:
const pattern = "__/__/____";
const patternFreeChar = "_";
const validDate = [
/^[0-3]$/,
/^(0[1-9]|[12]\d|3[01])$/,
/^(0[1-9]|[12]\d|3[01])[01]$/,
/^((0[1-9]|[12]\d|3[01])(0[13578]|1[02])|(0[1-9]|[12]\d|30)(0[469]|11)|(0[1-9]|[12]\d)02)$/,
/^((0[1-9]|[12]\d|3[01])(0[13578]|1[02])|(0[1-9]|[12]\d|30)(0[469]|11)|(0[1-9]|[12]\d)02)[12]$/,
/^((0[1-9]|[12]\d|3[01])(0[13578]|1[02])|(0[1-9]|[12]\d|30)(0[469]|11)|(0[1-9]|[12]\d)02)(19|20)/
]
/**
* Validate a date as your type.
* @param {string} date The date in format DDMMYYYY as a string representation.
* @throws {Error} When the date is invalid.
*/
function validateStartTypingDate(date) {
if ( !date ) return "";
date = date.substr(0, 8);
if ( !/^\d+$/.test(date) )
throw new Error("Please type numbers only");
if ( !validDate[Math.min(date.length-1,validDate.length-1)].test(date) ) {
let errMsg = "";
switch ( date.length ) {
case 1:
throw new Error("Day in month can start only with 0, 1, 2 or 3");
case 2:
throw new Error("Day in month must be in a range between 01 and 31");
case 3:
throw new Error("Month can start only with 0 or 1");
case 4: {
const day = parseInt(date.substr(0,2));
const month = parseInt(date.substr(2,2));
const monthName = new Date(0,month-1).toLocaleString('en-us',{month:'long'});
if ( month < 1 || month > 12 )
throw new Error("Month number must be in a range between 01 and 12");
if ( day > 30 && [4,6,9,11].includes(month) )
throw new Error(`${monthName} have maximum 30 days`);
if ( day > 29 && month === 2 )
throw new Error(`${monthName} have maximum 29 days`);
break;
}
case 5:
case 6:
throw new Error("We support only years between 1900 and 2099, so the full year can start only with 19 or 20");
}
}
if ( date.length === 8 ) {
const day = parseInt(date.substr(0,2));
const month = parseInt(date.substr(2,2));
const year = parseInt(date.substr(4,4));
const monthName = new Date(0,month-1).toLocaleString('en-us',{month:'long'});
if ( !isLeap(year) && month === 2 && day === 29 )
throw new Error(`The year you are trying to enter (${year}) is not a leap year. Thus, in this year, ${monthName} can have maximum 28 days`);
}
return date;
}
/**
* Check whether the given year is a leap year.
*/
function isLeap(year) {
return new Date(year, 1, 29).getDate() === 29;
}
/**
* Move cursor to the end of the provided input element.
*/
function moveCursorToEnd(el) {
if (typeof el.selectionStart == "number") {
el.selectionStart = el.selectionEnd = el.value.length;
} else if (typeof el.createTextRange != "undefined") {
el.focus();
var range = el.createTextRange();
range.collapse(false);
range.select();
}
}
/**
* Move cursor to the end of the self input element.
*/
function selfMoveCursorToEnd() {
return moveCursorToEnd(this);
}
const input = document.querySelector("input")
input.addEventListener("keydown", function(event){
event.preventDefault();
document.getElementById("date-error-msg").innerText = "";
// On digit pressed
let inputMemory = this.dataset.inputMemory || "";
if ( event.key.length === 1 ) {
try {
inputMemory = validateStartTypingDate(inputMemory + event.key);
} catch (err) {
document.getElementById("date-error-msg").innerText = err.message;
}
}
// On backspace pressed
if ( event.code === "Backspace" ) {
inputMemory = inputMemory.slice(0, -1);
}
// Build an output using a pattern
if ( this.dataset.inputMemory !== inputMemory ) {
let output = pattern;
for ( let i=0, digit; i<inputMemory.length, digit=inputMemory[i]; i++ ) {
output = output.replace(patternFreeChar, digit);
}
this.dataset.inputMemory = inputMemory;
this.value = output;
}
// Clean the value if the memory is empty
if ( inputMemory === "" ) {
this.value = "";
}
}, false);
input.addEventListener('select', selfMoveCursorToEnd, false);
input.addEventListener('mousedown', selfMoveCursorToEnd, false);
input.addEventListener('mouseup', selfMoveCursorToEnd, false);
input.addEventListener('click', selfMoveCursorToEnd, false);
<input type="text" placeholder="DD/MM/YYYY" />
<div id="date-error-msg"></div>
jsfiddle的链接: https://jsfiddle.net/d1xbpw8f/56/
祝你好运!
答案 6 :(得分:0)
我从这个线程决策Implement an input with a mask中提取了代码,并将其修改为IE10,并添加了setter和getter函数。
但我仅测试了电话面具
$(document).ready(function(){
var el_arr = document.querySelectorAll("[placeholder][data-slots]");
for (var el_ind=0; el_ind < el_arr.length; el_ind++ ){
var el = el_arr[el_ind];
var pattern = el.getAttribute("placeholder"),
slots = new Set(el.getAttribute("data-slots") || "_"),
prev = function(j){return Array.from(pattern, function(c,i){ return slots.has(c)? j=i+1: j;});}(0),
first = pattern.split('').findIndex(function(c){return slots.has(c);} ),
accept = new RegExp(el.getAttribute("data-accept") || "\\d", "g"),
clean = function(input){input = input.match(accept) || [];return Array.from(pattern, function(c){return input[0] === c || slots.has(c) ? input.shift() || c : c;});},
format = function(){
var elem = this;
var i_j_arr = [el.selectionStart, el.selectionEnd].map(function(i){
i = clean(el.value.slice(0, i)).findIndex(function(c){ return slots.has(c);});
return i<0? prev[prev.length-1]: elem.back? prev[i-1] || first: i;
});
el.value = clean(el.value).join('');
el.setSelectionRange(i_j_arr[0], i_j_arr[1]);
this.back = false;
},
// sdo added
get_masked_value = function(){
var input = this.value;
var ret=[];
for(var k in pattern){
if ( !input[k] )break;
if( slots.has(pattern[k]) && input[k]!=pattern[k]){
ret.push(input[k]);
}
}
return ret.join('');
},
set_masked_value = function(input){
var ret=[];
var index_in_value = 0;
for(var k in pattern){
if( slots.has(pattern[k]) && input[index_in_value]){
ret.push(input[index_in_value]);
index_in_value++;
}
else{
ret.push(pattern[k]);
}
}
this.value = ret.join('');
}
;
el.get_masked_value = get_masked_value;
el.set_masked_value = set_masked_value;
el.back = false;
el.addEventListener("keydown", function(event){ this.back = event.key === "Backspace";});
el.addEventListener("input", format);
el.addEventListener("focus", format);
el.addEventListener("blur", function() { return el.value === pattern && (el.value=""); });
}
});
答案 7 :(得分:0)
使用此代码实现掩码:
https://rawgit.com/RobinHerbots/jquery.inputmask/3.x/dist/jquery.inputmask.bundle.js
<input id="phn-number" class="ant-input" type="text" placeholder="(XXX) XXX-XXXX" data-inputmask-mask="(999) 999-9999">
jQuery( '#phn-number[data-inputmask-mask]' ).inputmask();
答案 8 :(得分:-1)
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/>
答案 9 :(得分:-1)
下面我描述我的方法。我在input
的输入中设置事件,以调用Masking()方法,该方法将返回我们在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;
}
答案 10 :(得分:-11)
使用此代码: -
<input type="text" placeholder="" data-mask="9999/99/99">