表單驗證:中文姓名、身分證、手機條碼、生日、信箱、手機、選擇縣市
Let's Write
Posted on June 27, 2022
本篇大綱
本篇要解決的問題
網站上蠻常會有表單功能的,像是聯絡我們、購物車,就會需要前端工程師先將欄位驗證好,當資料、格式都正確後,再調用 API 把表單送到後端去做處理,這樣子的流程會是比較好的 UX。最近的案子剛好要驗證很多的表單欄位,就順便整理成這篇,之後要用就可以 複製貼上 回頭查找。
除了表單驗證,本篇的 Demo 也會使用一些套件,讓出來的資料會是正確的格式,就不會寫驗證了,因為格式已經是對的。
本篇除了自己手寫的原生 JS,也會使用套件,都會附上套件的連結。
本篇最後完成的 Demo:https://letswritetw.github.io/letswrite-form-validation/
Demo 部份為了讓頁面好看,有用 daisyUI 這套 Tailwind CSS 的 framework。
中文姓名
這算是比較特別的需求,要求說姓名欄位的部份只能填寫中文名字,不能填寫英文。
August 在寫的時候也增加了限制:不能填寫數字、不能填寫特殊符號。
但…特殊符號有點麻煩,因為中文還有些人會打全形,因此過濾的部份就是濾掉幾個常用的符號。
<!-- HTML -->
<input id="js_name" type="text">
<!-- JS -->
<script>
function checkChName(el) {
el.addEventListener('input', e => {
setTimeout(() => {
return e.target.value = e.target.value.replace(/[a-zA-Z0-9]|[\w\s]|[!#$€£%&'"`()*+\-.\/::;;…,,。「」【】=<>?@{}\\\^|\[\]]/g, '')
}, 0)
}, false);
}
const jsName = document.getElementById('js_name');
checkChName(jsName);
</script>
簡單來說,就是 id
為 js_name
的 input
,在值有改變時,會把輸入的值濾掉英文、數字、指定的符號後,再回傳成值。
因為是寫原生的,所以寫的落落長,如果能用 Vue.js,直接寫進 watch
裡可以更簡短。
身分證字號、手機條碼
這部份就直接用套件了,上網查了一下身份證字號的規則,覺得自己寫好麻煩,既然有佛心工程師寫了套件,就直接使用囉~
使用的套件是:taiwan-id-validator
它總共可以驗證以下資料:
- 台灣身分證字號驗證
- 舊版臺灣地區無戶籍國民、外國人、大陸地區人民及香港或澳門居民之專屬代號
- 新版臺灣地區無戶籍國民、外國人、大陸地區人民及香港或澳門居民之專屬代號
- 公司統一編號驗證 (2021/10/28 新增新版統一編號檢查)
- 自然人憑證編號驗證
- 電子發票手機條碼驗證
- 電子發票捐贈碼驗證
是不是超多,本篇僅示範身分證字號、電子發票手機條碼這二個。
HTML
<!-- 身份證字號 -->
<input id="js_id" class="uppercase" type="text">
<!-- 手機條碼 -->
<input id="js_phoneId" class="uppercase" type="text">
JS
import {
isNationalIdentificationNumberValid, // 身分證字號
isEInvoiceCellPhoneBarcodeValid, // 手機條碼
} from 'taiwan-id-validator';
// 驗證身分證字號
const jsId = document.getElementById('js_id');
let value = jsId.value;
if(isNationalIdentificationNumberValid(value)) {
// 格式正確時
} else {
// 格式錯誤時
}
// 驗證手機條碼
const jsPhoneId = document.getElementById('js_phoneId');
let value = jsPhoneId.value;
if(isEInvoiceCellPhoneBarcodeValid(value)) {
// 格式正確時
} else {
// 格式錯誤時
}
身分證首字、手機條碼自動大寫
五歲能抬頭的朋友一定有發現到,上面 August 寫的 HTML 程式碼,在 input
上多加了 uppercase
這個 class。
身分證字號的第一個英文字母、手機條碼的英文字母,都是大寫,如果要使用者多按一個按鍵去切換大小寫,是不太好的 UX,因為每多一次點擊,就會多流失一點使用者的填單率。
所以更好的 UX 是不論使用者輸入大寫或小寫,我們都直接透過程式讓它自動轉為大寫。
方式很簡單。
- 在頁面 HTML 的部份,我們用
.uppercase
讓使用者看到的結果直接都是大寫 - 驗證資料時,用 JS 把使用者輸入的值轉成大寫後再去驗證
- 送資料時,也是透過 JS 把使用者輸入的值轉成大寫後再送出
所以上面的範例程式碼就可以改成:
HTML
<!-- 身份證字號 -->
<input id="js_id" class="uppercase" type="text">
<!-- 手機條碼 -->
<input id="js_phoneId" class="uppercase" type="text">
CSS
.uppercase {
text-transform: uppercase;
}
JS
import {
isNationalIdentificationNumberValid, // 身分證字號
isEInvoiceCellPhoneBarcodeValid, // 手機條碼
} from 'taiwan-id-validator';
// 驗證身分證字號
const jsId = document.getElementById('js_id');
let value = jsId.value.toLocaleUpperCase();
if(isNationalIdentificationNumberValid(value)) {
// 格式正確時
} else {
// 格式錯誤時
}
// 驗證手機條碼
const jsPhoneId = document.getElementById('js_phoneId');
let value = jsPhoneId.value.toLocaleUpperCase();
if(isEInvoiceCellPhoneBarcodeValid(value)) {
// 格式正確時
} else {
// 格式錯誤時
}
生日 / 出生年月日
選日期的部份,August 也是用套件,用過的有二套。
如果不在意頁面多引用 jQuery,推薦這套:fDatepicker。
他可以讓使用者先從「年」開始選,選完後再選「月」,之後再選「日」,操作上比較直覺。
如果不想用 jQuery,想用原生,那可以用本篇 Demo 使用的這套:Vanilla JS Datepicker。
August 覺得這套操作體驗上沒有 fDatepicker 來的好,但它的優點就是原生。
如果有用過更好的日期套件要推薦的話,歡迎留言~
關於出生年月日的欄位,為了要統一輸出的格式,因此是用套件來產生選單讓使用者選取。
但這樣還不夠,還需要一道工,就是生日的 input
不能讓使用者自行填寫。
HTML
<input id="js_birthday" type="text" readonly inputmode="none">
readonly
,就是讓這個欄位只能讀不能寫。
inputmode="none"
,就是在手機時不讓小鍵盤跳出來。
至於為什麼這邊 August 是推薦 readonly
而不是 disabled
?
在工程師永遠的好朋友 stackoverflow 上有提到,我們按 tab 鍵切換選定的元素時,readonly
可以被 focus,而 disabled
則無法,為了讓桌機時操作順暢,這邊選用的是 readonly
。
JS
import { Datepicker } from 'vanillajs-datepicker'
// 引用中文
import zhTW from 'vanillajs-datepicker/locales/zh-TW'
Object.assign(Datepicker.locales, zhTW);
const birthday = document.getElementById('js_birthday');
const datepicker = new Datepicker(birthday, {
format: 'yyyy-mm-dd',
language: 'zh-TW'
});
format
的部份可以改成後端需要的格式。
E-mail 電子信箱
驗證 email 比較單純,就是驗證輸入的格式正不正確。
HTML
<input id="js_email" type="email" inputmode="email">
inputmode="email"
,是讓手機時跳出的小鍵盤,是專門輸入 email 用的,iPhone 上看會像這樣:
JS
const jsEmail = document.getElementById('js_email');
const rex = /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z]+$/;
if(jsEmail.value.search(rex) === -1) {
// 錯誤
}
else {
// 正確
}
手機
驗證手機也很單純,就是看格式正不正確。
HTML
<input id="js_phone" type="tel" inputmode="tel">
inputmode="tel"
,是讓手機時跳出的小鍵盤,是專門輸入電話號碼用的,iPhone 上看會像這樣:
JS
const jsPhone = document.getElementById('js_phone');
const rex = /^(09)[0-9]{8}$/;
if(jsPhone.value.search(rex) === -1) {
// 錯誤
}
else {
j// 正確
}
手機限輸入 10 碼
手機號碼總共 10 碼,我們自己在網購時都知道,有時就是會手抖或手殘不小心多按一碼造成錯誤。
因此 August 在製作表單時,也會把手機這欄加入只能填寫 10 碼的 JS:
const jsPhone = document.getElementById('js_phone');
jsPhone.addEventListener('input', e => {
if(e.target.value.length > 10) {
e.target.value = e.target.value.slice(0, 10);
}
});
選擇縣市
通常,如果讓使用者填寫地址時,縣市的部份是自己打字,就會看到什麼叫世界末日,光一個台北市,就會看到「台北、台北市、臺北、臺北市、北市」。
如果還要使用者自己去找郵遞區號,就會更慘,不是憑記憶填不然就是乾脆放棄不填了。
幸好,工程師界裡總有希望世界和平的大神,選擇縣市的部份推薦套件:jQuery-TWzipcode*。*
雖然名稱上有可以再戰十年的「jQuery」,但不用擔心,它有出原生 JS 版的。
進到套件的 GitHub,會看見 JS 檔案有三個:
- jquery.twzipcode.js:jQuery + 未壓縮版
- jquery.twzipcode.min.js:jQuery + 壓縮版
- twzipcode.js:原生 JS + 未壓縮版
文件的部份,jQuery 版本的就看 GitHub 上 README.md 的說明。原生的就看上面提供的 Demo。
因為原生的部份不是寫成 export,所以引用時就在頁面上直接引用。
HTML
<div class="twzipcode">
<!-- 選擇縣市 -->
<div data-role="county">
<!-- 選擇鄉鎮市區 -->
<div data-role="district">
<!-- 郵遞區號 -->
<div data-role="zipcode">
</div>
<script src="/path/twzipcode.js"></script>
JS
const twzipcode = new TWzipcode(".twzipcode", {
zipcode: {
readonly: true
}
});
郵遞區號因為套件會自動產生,因此建議是加上 readonly: true
讓使用者無法自行輸入。
範例及原始碼
本篇的範例及原始碼有放在 GitHub 上,取用前麻煩分享本篇,或是按個星星,你的小小動作對本站都是大大的鼓勵。
Demo:https://letswritetw.github.io/letswrite-form-validation/
原始碼:https://github.com/letswritetw/letswrite-form-validation
Posted on June 27, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.