跳至主要内容

[WebAPIs] 表單驗證與取值 form validation and value

keywords: input, form

HTML Element @ MDN HTML Input element @ MDN

概念

  • 一般來說 client-side 的表單驗證因為使用者能夠得到立即的回饋,所以較為 user-friendly。在 client-side 的表單驗證中,又可以分成用 HTML 內建的表單驗證或用 JS 製作表單驗證,前者效能較好,後者較能進行客制化的驗證。
  • server-side 的表單驗證雖然對使用者來說較不友善,但卻是必要的,因為前端的東西容易遭到使用者竄改。
  • 因此,最常見的是同時使用 client-side 和 server-side 表單驗證。
  • 當表單送出驗證有效時,會在表單欄位增加 :valid 的偽元素;若無效則會新增 :invalid 的偽元素。

HTML 元素

Input Text

keywords: required, pattern, minlength, maxlength
<!-- specify "minlength" and "maxlength" -->
<input
type="text"
id="username"
name="name"
size="10"
placeholder="Username"
required
minlength="4"
maxlength="8"
/>

<!-- specify a "pattern" -->
<input type="text" id="username" name="name" size="45" required pattern="[a-z]{4,8}" />

<textarea> 一樣有提供 maxlength 但是不提供 pattern

Input Number

keywords: required, min, max, step
<input type="number" id="number" name="amount" value="1" min="1" max="10" step="0.1" />

Input Number 並不支援使用 pattern @ MDN

表單取值

一般表單中的 <input /> 都可以直接透過 value 取得該內容,除了一些特殊的 radiofile 的類型不是直接透過 value 取得:

/* text, textarea, range, select 都可以透過 value 取值,但 multiple select 不行 */
const inputElements = document.querySelectorAll(
'input[type="text"], input[type="range"], select, textarea',
);
[...inputElements].forEach((input) => console.log(`${input.type}: ${input.value}`));

/* file */
const fileInput = document.querySelector('input[type="file"]');
fileInput.type; // 'file'
fileInput.value; // 'C:\fakepath\IMG_20190526_172551.jpg'
fileInput.files; // FileList Object

/* radio, checkbox */
const checkInput = document.querySelector('input[type="radio"], input[type="checkbox"]');
checkInput.checked; // true or false

客制化表單驗證訊息

然而,透過 HTML 自動產生的表單驗證訊息有些特性:

  • 沒有 HTML 原生方法可以直接修改樣式。
  • 另外,不同的瀏覽器和不同的地區看到的也會是不同的訊息內容。

因此若想客制化表單樣式和訊息得搭配使用 JS。

如果只是想要做到客制化錯誤訊息,可以使用 setCustomValidity 參考下述的作法:

var email = document.getElementById('mail');

email.addEventListener('input', function (event) {
if (email.validity.typeMismatch) {
email.setCustomValidity('I expect an e-mail, darling!');
} else {
email.setCustomValidity('');
}
});

如果想要做到更多客制化的功能,可以參考 HTML5 constraint validation API ,在使用 JavaScript 客制化表單樣式時,需要為表單添加 novalidate 屬性來關掉瀏覽器預設的驗證行為,但這麼做並不會關閉調可以用的表單驗證 API,也不會影響到 CSS 偽類 :valid, :invalid, :in-range, out-of-range,因此我們還是可以使用這些樣式:

<!-- HTML -->
<form novalidate>
<p>
<label for="mail">
<span>Please enter an email address:</span>
<input type="email" id="mail" name="mail" />
<span class="error" aria-live="polite"></span>
</label>
</p>
<button>Submit</button>
</form>

JS 部分則可以使用 inputElement.validity.valid 來驗證使用者輸入資料的有效性,當內容無效時,可以為 .error 添加 .active 來促發錯誤訊息:

var form = document.getElementsByTagName('form')[0];
var email = document.getElementById('mail');
var error = document.querySelector('.error');

email.addEventListener(
'input',
function (event) {
if (email.validity.valid) {
error.innerHTML = ''; // Reset the content of the message
error.className = 'error'; // Reset the visual state of the message
}
},
false,
);

form.addEventListener(
'submit',
function (event) {
if (!email.validity.valid) {
error.innerHTML = 'I expect an e-mail, darling!';
error.className = 'error active';
event.preventDefault();
}
},
false,
);

參考

Learn HTML Forms - Form Validations @ MDN