it-swarm.com.de

Implementieren Sie eine Eingabe mit einer Maske

Ich möchte eine Maske für ein Textfeld input implementieren, das ein Datum akzeptiert. Der maskierte Wert sollte direkt in input angezeigt werden.

Etwas wie das:

<input type='text' value='____/__/__'>

Ich habe die Maske in diesem Beispiel als Wert geschrieben, aber ich möchte, dass Personen ein Datum schreiben können, ohne / oder - einzugeben, um Monate, Jahre und Tage zu trennen. Der Benutzer sollte in der Lage sein, Zahlen in das angezeigte Feld einzugeben, während die Maske das Format automatisch erzwingt, wenn der Benutzer es eingibt.

Ich habe dieses Verhalten auf anderen Websites gesehen, weiß aber nicht, wie es funktioniert oder wie ich es selbst implementieren kann.

41

Eingabemasken können mithilfe einer Kombination der Ereignisse keyup und der HTMLInputElementvalue-, selectionStart- und selectionEnd-Eigenschaft implementiert werden. Hier ist eine sehr einfache Implementierung, die das tut, was Sie wollen. Es ist sicherlich nicht perfekt, funktioniert aber gut genug, um das Prinzip zu demonstrieren:

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/>

( In JSFiddle anzeigen )

Es gibt auch eine Reihe von Bibliotheken, die diese Funktion ausführen. Einige Beispiele sind:

34
Ajedi32

Nachdem ich den ganzen Beitrag gelesen habe, habe ich meine eigene Implementierung gemacht, ich hoffe, jemandem zu helfen:

Die Idee ist,

  1. erlaube nur die Eingabe von Zahlen. (Tastendruckereignis)
  2. holen Sie sich alle Zahlen in einem Array
  3. ersetzen Sie jedes Zeichen "_" der Maske durch eine Zahl aus dem Array in einer Schleife

Verbesserungen sind willkommen.

/**
 * 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="e.g (123) 456-7890" pattern="^\([0-9]{3}\)\s[0-9]{3}-[0-9]{4}$">
19
Rodney Salcedo

Sie können dies auch mit der systemeigenen Methode von JavaScripts erreichen. Es ist ziemlich einfach und erfordert keine zusätzliche Bibliothek zum Importieren.

<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">
10
shubhamkes

Sie können auch meine Implementierung ausprobieren, bei der beim Eingeben des Inhalts nach jedem Tastendruck keine Verzögerung auftritt und die Rücktaste und das Löschen vollständig unterstützt werden.

Sie können es online ausprobieren: 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
Cecilk Cao

Eine Lösung, die auf das input -Ereignis anstelle von Schlüsselereignissen (wie keyup) reagiert, sorgt für einen reibungslosen Ablauf (keine Wackelbewegungen) und funktioniert auch, wenn Änderungen ohne Tastatur vorgenommen werden (Kontextmenü, Ziehen mit der Maus) , anderes Gerät...).

Der folgende Code sucht nach Eingabeelementen mit den Attributen placeholder und data-slots. Letzteres sollte die Zeichen im Platzhalter definieren, die als Eingabeschlitz vorgesehen sind, z. B. "_". Ein optionales data-accept -Attribut kann mit einem regulären Ausdruck versehen werden, der definiert, welche Zeichen in einem solchen Slot zulässig sind. Die Standardeinstellung ist \d, d. H. Ziffern.

// 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>
3
trincot

Unten beschreibe ich meine Methode. Ich setze event bei der Eingabe in input, um die Masking () - Methode aufzurufen, die eine formatierte Zeichenfolge des in input eingefügten String zurückgibt.

Html:

<input name="phone" pattern="+373 __ ___ ___" class="masked" required>

JQ: Hier setzen wir ein Ereignis für die Eingabe:

$('.masked').on('input', function () {
    var input = $(this);
    input.val(Masking(input.val(), input.attr('pattern')));
});

JS: Funktion, die den String nach Muster formatiert;

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;
}
0
Dumitru Boaghi

Ich habe vor einiger Zeit eine ähnliche Lösung geschrieben.
Natürlich ist es nur ein PoC und kann weiter verbessert werden.

Diese Lösung umfasst die folgenden Funktionen:

  • Nahtlose Zeicheneingabe
  • Musteranpassung
  • Live-Validierung beim Tippen
  • Vollständige Datumsvalidierung (einschließlich korrekter Tage in jedem Monat und Berücksichtigung des Schaltjahres)
  • Beschreibende Fehler, damit der Benutzer versteht, was vor sich geht, während er kein Zeichen eingeben kann
  • Positionieren Sie den Cursor und verhindern Sie die Auswahl
  • Platzhalter anzeigen, wenn der Wert leer ist
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>

Ein Link zu jsfiddle: https://jsfiddle.net/d1xbpw8f/56/

Viel Glück!

0
Slavik Meltser
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/>
0
Vishnu Kant