2012-09-25 15 views
37

Vorrei implementare una maschera per un campo di input di testo che accetta una data. Il valore mascherato dovrebbe essere visualizzato direttamente all'interno dell'input.Come implementare un input con una maschera

Qualcosa di simile a questo:

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

ho scritto la maschera come un valore in questo esempio, ma il mio intento è quello di permettere alle persone di scrivere una data senza digitare / o - per mesi separati, anni e giorni. L'utente dovrebbe essere in grado di inserire numeri nel campo visualizzato, mentre la maschera impone il formato automaticamente quando l'utente digita.

Ho visto questo comportamento su altri siti, ma non ho idea di come funzioni o come implementarlo da solo.

risposta

28

Le maschere di input possono essere implementate utilizzando una combinazione della manifestazione keyup, e le HTMLInputElementvalue, selectionStart e selectionEnd proprietà. Ecco un'implementazione molto semplice che fa parte di ciò che desideri. Non è certamente perfetto, ma funziona abbastanza bene per dimostrare il principio:

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

(View in JSFiddle)

ci sono anche una serie di librerie là fuori che svolgono questa funzione. Alcuni esempi includono:

+1

Il cursore si sposta a sinistra quando si va oltre un certo char nella maschera (ad esempio, trattino o staffa) – Andree

+0

@Andree corretta , questo è uno dei motivi per cui ho detto "non è certamente perfetto, ma funziona abbastanza bene per dimostrare il principio". Un'implementazione del mondo reale dovrebbe essere più complicata per tenere conto di casi limite come quello che peggiora l'esperienza dell'utente. – Ajedi32

+0

C'è un motivo per usare 'keyup' invece dell'evento' keydown'? – fbynite

13

Dopo aver letto tutto dopo, ho fatto la mia realizzazione, spero di aiutare a qualcuno :

L'idea è,

  1. consentire solo numeri di ingresso. (Pressione di un tasto)
  2. ottenere tutti i numeri in un array
  3. sostituire ogni carattere "_" di maschera da un numero da array in un ciclo

miglioramenti sono i benvenuti.

/** 
 
* charCode [48,57] \t Numbers 0 to 9 
 
* keyCode 46 \t \t \t "delete" 
 
* keyCode 9 \t \t \t "tab" 
 
* keyCode 13 \t \t \t "enter" 
 
* keyCode 116 \t \t \t "F5" 
 
* keyCode 8 \t \t \t "backscape" 
 
* keyCode 37,38,39,40 \t Arrows 
 
* keyCode 10 \t \t \t (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}$">

+0

Rendo generico il nome della funzione e utilizzo la logica simile utilizzata da Ajedi32 e ottenendo la maschera dall'attributo "data-mask". In questo modo non stai mascherando solo il numero di telefono ma qualsiasi tipo fornito nell'attributo maschera dati – programmerboy

+0

@programmerboy È una buona idea! –

10

È possibile raggiungere questo obiettivo anche utilizzando il metodo nativo di JavaScript. È piuttosto semplice e non richiede alcuna libreria aggiuntiva da importare.

<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"> 
+2

Ottima soluzione ... Tranne quando si tenta di utilizzare backspace. :) Quindi è necessaria una piccola modifica per gestirlo. – derekadk

+0

Modifica secondaria per il backspace della maniglia !!! SridharKritha

-6

di questo codice: -

<input type="text" placeholder="" data-mask="9999/99/99"> 
+9

Questo non fa nulla. –

+1

Questo non fa nulla senza il jQuery Mask Plugin che puoi trovare qui ... https://igorescobar.github.io/jQuery-Mask-Plugin –

+2

L'HTML da solo non può fare qualcosa del genere, per favore considera una risposta migliore, forse hai dimenticato di menzionare qualche componente aggiuntivo o Javascript –

2

Ecco un 500-linee jQuery plugin per rendere le maschere su campi modulo e gli elementi HTML: DEMO

Si può capire le basi studiando il suo codice sorgente: https://github.com/igorescobar/jQuery-Mask-Plugin

+0

btw: Ho scritto un'implementazione simile leggera (JavaScript semplice) che è pubblicata su https: // github.com/eugenmihailescu/myinputmask –

2

Si può anche provare la mia implementazione, che non ha ritardo dopo ogni pressione di un tasto quando digitando il contenuto e ha pieno supporto per backspace ed elimina.

Si può provare on-line: 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> 
0
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

Sarebbe utile se inserisse un testo introduttivo che spiega il tuo codice e come risponderebbe alla domanda. –

Problemi correlati