
⚙️ Kuinka estää ei-toivotut merkkisyötteet INPUT-kentässä JavaScriptillä
Rekisteröintilomake, puhelinkenttä, luettelohaku: käyttäjä klikkaa INPUT-kenttää ja kirjoittaa mitä tahansa. Kirjaimia sinne, missä odotat numeroita. Erikoismerkkejä tilausnumerossa. Emojeita sähköpostikentässä. Lopputulos: roskaa tietokannassa, rikkinäisiä kyselyitä, backendin validointi kaatuu virheeseen.
Ongelma ratkeaa frontendissa 15 koodirivillä. Ei liitännäisiä, ei kirjastoja, pelkkää JavaScriptiä tai pari HTML-attribuuttia. Alla on kolme toimivaa lähestymistapaa: nopeasta HTML5-ratkaisusta hienojakoiseen keydown-suodatukseen, valmiine esimerkkeineen yleisimpiin tilanteisiin.
💡 Pikakatsaus:
- Tutkimme, milloin HTML-attribuutit
pattern,inputmodejatyperiittävät ja milloin tarvitaan JavaScriptiä - Kirjoitamme "vain numerot" -suodattimen jQuerylla ja puhtaalla JS:llä, molemmat versiot rivi riviltä selitettynä
- Lisäämme suojauksen liittämistä vastaan Ctrl+V:n ja kontekstivalikon kautta
- Rakennamme yleiskäyttöisen mallifunktion kaikenlaisiin rajoituksiin: kirjaimet, latinalaiset merkit, mukautetut maskit
HTML5: mitä voit tehdä ilman yhtäkään JavaScript-riviä
Yksinkertaisin ja luotettavin tapa rajoittaa syötettä on kertoa selaimelle, mitä kentässä tarkalleen odotetaan. Nykyselaimet ymmärtävät kolme keskeistä attribuuttia, jotka kattavat useimmat tavalliset tehtävät.
type, ensisijainen suodatin. type="number" sallii vain numerot, miinuksen ja desimaalierottimen. type="tel" näyttää mobiililaitteissa numeronäppäimistön. type="email" tarkistaa @-merkin lomakkeen lähetyksessä. type="url" vaatii protokollan. Tämä ei estä syöttämistä kokonaan, mutta tarjoaa oikean näyttönäppäimistön ja perusvalidoinnin lähetettäessä.
pattern, säännöllinen lauseke kentässä. Attribuutti hyväksyy regex-lausekkeen ja validoi arvon lomakkeen lähetyksessä:
1 <input type="text" pattern="[0-9]{6}" placeholder="Six digits" title="Exactly 6 digits">
Selain estää lähetyksen, jos arvo ei vastaa lauseketta. Huono puoli: pattern ei estä kiellettyjen merkkien syöttämistä; se vain validoi lopputuloksen. Käyttäjä voi kirjoittaa "abc", ja näkee virheen vasta yrittäessään lähettää lomakkeen.
inputmode, oikea näppäimistö mobiilissa. inputmode="numeric" avaa numeronäppäimistön, mutta ei estä kirjainten syöttämistä. inputmode="decimal" lisää erottimen. Hyödyllinen yhdessä JavaScript-suodattimen kanssa: näppäimistö on jo oikea, ja JS hoitaa loput.
Mitä valita. Jos haluat todella estää kiellettyjen merkkien syöttämisen reaaliajassa, HTML-attribuutit eivät riitä. Siirrytään JavaScriptiin.
JavaScript: näppäinpainallusten esto keydownilla
keydown-lähestymistapa nappaa jokaisen näppäinpainalluksen ennen kuin merkki ilmestyy kenttään. Jos näppäin ei ole sallittujen listalla, event.preventDefault() estää sen.
Vaihtoehto 1: jQuery, vain numerot
Koodi kiinnitetään INPUT-kenttään id:n perusteella, sallii numerot ja toimintonäppäimet (backspace, nuolet, Tab) ja estää kaiken muun:
1 $(document).ready(function() { 2 $("#phone_input").keydown(function(event) { 3 // Service keys — let them through 4 if (event.keyCode === 46 || event.keyCode === 8 || 5 event.keyCode === 9 || event.keyCode === 27 || 6 (event.keyCode === 65 && event.ctrlKey === true) || 7 (event.keyCode >= 35 && event.keyCode <= 39)) { 8 return; 9 } 10 // Block everything except digits (main block and numpad) 11 if ((event.keyCode < 48 || event.keyCode > 57) && 12 (event.keyCode < 96 || event.keyCode > 105)) { 13 event.preventDefault(); 14 } 15 }); 16 });
Tässä mitä tapahtuu rivi riviltä: keyCode 46 (Delete), 8 (Backspace), 9 (Tab), 27 (Escape), 65 + Ctrl (valitse kaikki), 35..39 (Home, End, nuolet). Sitten tulevat päänumerolohko 48..57 (0..9) ja numeronäppäimistö 96..105. Mikään, mikä ei osu näihin väleihin, saa preventDefault-kutsun.
Täydellinen näppäinkooditaulukko Cambia Researchissa.
Vaihtoehto 2: puhdas JavaScript, vain numerot
Sama asia ilman jQuerya, käyttäen onkeypress-tapahtumaa. Tämä versio on tiiviimpi eikä vedä mukanaan kirjastoa:
1 document.getElementById("phone_input").onkeypress = function(event) { 2 event = event || window.event; 3 if (event.charCode && (event.charCode < 48 || event.charCode > 57)) { 4 return false; 5 } 6 };
charCode tarkistaa, että tapahtumalla on tulostuva merkki; toimintonäppäimet (nuolet, backspace) menevät läpi automaattisesti, koska niiden charCode on 0. Numerot: 48..57, kaikki muu palauttaa false.
Tärkeää: keyCode on merkitty vanhentuneeksi. Nykyaikaisessa koodissa on parempi käyttää event.key-ominaisuutta, joka palauttaa merkkijonon näppäimen nimellä eikä riipu näppäimistöasettelusta:
1 element.addEventListener("keydown", function(event) { 2 // Allow digits, Backspace, Delete, arrows, Tab 3 const allowedKeys = [ 4 "Backspace", "Delete", "Tab", "Escape", 5 "ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", 6 "Home", "End" 7 ]; 8 if (allowedKeys.includes(event.key)) return; 9 // Ctrl+A / Ctrl+C / Ctrl+V 10 if (event.ctrlKey) return; 11 // Only digits 12 if (!/^[0-9]$/.test(event.key)) { 13 event.preventDefault(); 14 } 15 });
event.key-lähestymistapa on selkeälukuisempi eikä vaadi numerokoodien ulkoa opettelua. Mutta vanhempien selainten tukemiseen yllä oleva keyCode-versio toimii edelleen.
Liittämisen esto: Ctrl+V:n ja kontekstivalikon nappaaminen
keydown nappaa näppäinpainallukset, mutta käyttäjä voi liittää tekstiä Ctrl+V:llä tai hiiren oikealla napsautuksella → "Liitä". Hän kopioi "abc123" vain numeroita sallivaan kenttään, ja puolet siitä meni läpi.
Ratkaisu on input-tapahtuma. Se laukeaa MINKÄ tahansa kentän arvon muutoksen jälkeen: manuaalinen syöttö, liittäminen, automaattinen täyttö, tekstin raahaus ja pudotus. Suodatamme lopullisen arvon säännöllisellä lausekkeella:
1 document.getElementById("digits_only").addEventListener("input", function(event) { 2 this.value = this.value.replace(/[^0-9]/g, ""); 3 });
Siinä kaikki. Yksi rivi, eikä yksikään ei-numero pääse kentän läpi, riippumatta siitä miten se sinne joutui. Kirjaimille: replace(/[^a-zA-Zа-яА-ЯёЁ]/g, ""). Latinalaisille merkeille: replace(/[^a-zA-Z]/g, "").
Yhdistetty lähestymistapa (kultainen keskitie). keydown antaa välittömän palautteen (näppäin "ei painu"), kun taas input suojaa liittämiseltä. Käytä molempia käsittelijöitä:
1 const field = document.getElementById("digits_only"); 2 3 field.addEventListener("keydown", function(event) { 4 const allowed = ["Backspace", "Delete", "Tab", "Escape", 5 "ArrowLeft", "ArrowRight", "Home", "End"]; 6 if (allowed.includes(event.key)) return; 7 if (event.ctrlKey) return; 8 if (!/^[0-9]$/.test(event.key)) event.preventDefault(); 9 }); 10 11 field.addEventListener("input", function() { 12 this.value = this.value.replace(/[^0-9]/g, ""); 13 });
Ensimmäinen käsittelijä katkaisee kielletyt näppäinpainallukset välittömästi. Toinen siivoaa jäänteet liittämisen ja automaattisen täytön jälkeen.
Valmis malli kaikenlaisiin rajoituksiin
Rakennetaan funktio, joka ottaa INPUT-kentän ja sallittujen merkkien säännöllisen lausekkeen. Se toimii puhelinnumeroille, postinumeroille, käyttäjätunnuksille, SKU-hauille:
1 function restrictInput(element, allowedPattern) { 2 element.addEventListener("keydown", function(event) { 3 const serviceKeys = [ 4 "Backspace", "Delete", "Tab", "Escape", 5 "ArrowLeft", "ArrowRight", "Home", "End" 6 ]; 7 if (serviceKeys.includes(event.key)) return; 8 if (event.ctrlKey && ["a", "c", "v", "x", "z"].includes(event.key.toLowerCase())) return; 9 if (!allowedPattern.test(event.key)) event.preventDefault(); 10 }); 11 12 element.addEventListener("input", function() { 13 // Build a global pattern from the provided one and clean 14 const globalPattern = new RegExp( 15 allowedPattern.source.replace("^", "").replace("$", ""), 16 "g" 17 ); 18 // Remove everything that does NOT match the pattern 19 const inverted = new RegExp( 20 "[^" + allowedPattern.source.slice(1, -1) + "]", "g" 21 ); 22 this.value = this.value.replace(inverted, ""); 23 }); 24 }
Käyttö:
1 // Digits only 2 restrictInput(document.getElementById("phone"), /^[0-9]$/); 3 // Latin letters only without spaces 4 restrictInput(document.getElementById("login"), /^[a-zA-Z]$/); 5 // Letters and digits 6 restrictInput(document.getElementById("postal"), /^[a-zA-Z0-9]$/);
Funktio ei riipu jQuerysta, toimii kaikissa nykyselaimissa ja kattaa kolme skenaariota: manuaalinen syöttö (keydown), liittäminen (input), automaattinen täyttö (input).
Huom: keydown ei laukea virtuaalinäppäimistöillä joissakin mobiililaitteissa; siellä input jää ainoaksi suojaksi. Siksi kaksi käsittelijää yhdessä ei ole redundanssia vaan välttämättömyys.
Yllä oleva video on erittely lomakkeen validoinnista puhtaalla JavaScriptillä Web Dev Simplifiedilta. Se kattaa sisäänrakennetun Constraint Validation API:n, mukautetut virheilmoitukset ja virheellisten kenttien tyylittelyn, loistava täydennys tässä kuvatuille lähestymistavoille.
⁉️🤔 Usein kysytyt kysymykset
Miksei vain käyttäisi type="number"-attribuuttia?
type="number"salliie- jaE-merkkien (eksponentti), plussan, miinuksen ja pisteen syöttämisen. Kaikki nämä ovat kelvollisia merkkejä liukuluvuille ja eksponenttimuodolle. Puhelinkenttään tai postinumeroon ne ovat tarpeettomia. Lisäksi selaimet käsittelevät ei-numeerista syötettä eri tavoin: jotkut päästävät sen hiljaa läpi, toiset näyttävät virheen vasta lähetettäessä.
Voiko liittämisen Ctrl+V:llä estää kokonaan?
Liittämisen täydellinen estäminen on huono käytäntö. Se rikkoo käyttökokemuksen eikä suojaa muita liittämistapoja vastaan (kontekstivalikko, raahaus ja pudotus). Oikea lähestymistapa: salli liittäminen, mutta siivoa tulos välittömästi
input-käsittelijällä, kuten yllä olevassa osiossa näytettiin.
Entä selaimen automaattinen täyttö?
Automaattinen täyttö laukeaa ennen
keydown- jainput-tapahtumia; selain lisää arvon suoraan.input-käsittelijä nappaa tämänkin tapauksen: arvo ilmestyy kenttään, sitten se suodatetaan välittömästi. Jos automaattinen täyttö häiritsee (lisää kirjaimia puhelinkenttään), lisääautocomplete="off"-attribuutti INPUT-kenttään.
Toimiiko tämä mobiililaitteilla?
Kyllä, mutta yhdellä varauksella: virtuaalinäppäimistöt eivät aina tuota
keydown-tapahtumaa odotetuillakeyCode- jakey-arvoilla.input-käsittelijä toimii luotettavasti kaikkialla. Mobiiilissa aseta INPUT-kenttääninputmode="numeric"taiinputmode="decimal"; käyttäjä saa oikean näppäimistön, vaikkakeydown-suodatin ei laukeaisikaan.
Miten välilyönnit estetään?
Lisää välilyönti kiellettyjen merkkien luokkaan:
replace(/[^0-9a-zA-Z]/g, "")poistaa kaiken paitsi numerot ja latinalaiset kirjaimet, mukaan lukien välilyönnit. Tai eksplisiittisesti:this.value = this.value.replace(/\s/g, "")poistaa kaikki välilyönnit, sarkaimet ja rivinvaihdot.
Mikä lähestymistapa valita omaan tehtävään

Jos lomake on yksinkertainen eivätkä pari väärää merkkiä aiheuta kriittistä vahinkoa, käytä HTML5:tä: type, pattern ja inputmode kattavat perusskenaariot ilman yhtäkään JS-riviä. Nopea, natiivi, ei riippuvuuksia.
Jos reaaliaikainen hallinta ja välitön reaktio jokaiseen näppäinpainallukseen on tärkeää, käytä keydown + input -yhdistelmää. Ensimmäinen estää näppäinpainallukset, toinen siivoaa liittämisen seuraukset. Yllä olevan osion yleiskäyttöinen mallifunktio mukautuu mihin tahansa kenttään minuutissa.
Pääsääntö: älä estä liittämistä kokonaan. Se ärsyttää käyttäjiä eikä tarjoa todellista suojaa. Siivoa tulos liittämisen jälkeen sen kieltämisen sijaan.



