HTML5 給我們帶來了很多非常好的優勢。除了統一錯誤模型、引入新語義標簽或簡化文檔類型等常見問題之外,最大的改進之一是表單的約束驗證。如果沒有表單,網絡會是什么樣子?
約束驗證試圖提高 Web 表單的可用性。瀏覽器可以直接告知用戶無效值的可能性,而不是將表單發送到服務器,然后將其評估為無效,返回到客戶端并最終由用戶進行調整。這不僅減少了網絡通信,還提高了頁面的可用性。
需要注意的是,約束驗證不能取代服務器端驗證。此外,基于 JavaScript 的解決方案可能仍然有用。一般來說,我們總是必須實現服務器端驗證。如果我們使用良好的架構,服務器上的模型約束將自動反映在傳輸的 HTML 代碼中。這樣我們就可以免費獲得約束驗證。現在我們可以使用 JavaScript 進一步增強體驗,它既可以充當約束驗證的補充,也可以充當填充。
我們將從非驗證表單開始我們的旅程。然后我們將集成一個基于 JavaScript 的解決方案。最后介紹一下HTML5的約束驗證。在最后一節中,我們將了解可能遇到的跨瀏覽器奇怪現象。
非驗證表單提交
最經典的 HTML 表單版本是不帶有任何客戶端驗證邏輯的版本。我們只需要提供一個標準的形式,不需要任何特殊的屬性。正如簡介中已經指出的,我們需要始終特別注意這種表單提交。
盡管我們確實希望保護客戶端上已經存在的表單,但我們永遠無法確定所提交數據的狀態。保護和增強服務器上的表單驗證的技術很大程度上取決于所使用的編程框架和語言。因此我們將跳過這樣的討論。相反,我們現在將討論一般的表單提交。
在《精通HTML5》系列的第二部分中我們已經提到了表單編碼類型的重要性。我們還研究了三種成熟的編碼類型。剩下的問題是:這些價值觀實際上是如何建立的?瀏覽器的確切行為取決于為 action
指定的協議。為了簡單起見,我們現在假設 HTTP 或 HTTPS。
原則上,瀏覽器有兩個選項:
- 更改操作以攜帶表單的值。
通過請求正文提交值。
兩者的程序大致相同。簡而言之,我們發現以下步驟:
- 使用正確的編碼構建數據集。
使用數據集和編碼類型創建請求。
發送請求。
表單數據集的構建意味著一些微妙的問題,但這些問題并不是很為人所知。例如,如果單擊按鈕來提交表單,情況就會有所不同。在這種情況下,按鈕的值將傳輸到服務器。這可用于確定按下了哪個按鈕。
登錄后復制登錄后復制登錄后復制
如果我們按下第一個按鈕,那么以下內容將被發送到服務器。
foo=bar
登錄后復制
從 JavaScript 觸發表單提交將導致不傳輸任何內容。 JavaScript 代碼使用 HTMLFormElement
實例的 submit()
方法。
另一個有趣的方面是使用 image
類型提交輸入元素的單擊坐標。 image
輸入類型不久前非常流行,人們認為檢查用戶點擊的位置是個好主意。也許所顯示的圖像表明了幾種可能性。然后服務器將負責評估用戶的請求。
以下示例說明了此行為。
登錄后復制登錄后復制登錄后復制
如果我們點擊圖片提交表單,就會考慮foo
的數據。僅當值存在時才會插入名稱-值對。此外,我們需要命名輸入元素,否則不會傳輸任何內容。
請求的內容可能類似于以下代碼片段。
foo.x=71&foo.y=38&foo=bar
登錄后復制
此外,我們應該注意不考慮禁用字段。這是有道理的。因此,下面的表格考慮了具有兩個輸入字段(一個啟用和一個禁用)的前兩個示例,可以構建為概念證明。
以編程方式提交表單將導致傳輸單個值。
基本表單驗證
即使沒有約束驗證或 JavaScript,瀏覽器也已經為我們提供了一些簡單的表單驗證。正如我們之前所看到的,表單的狀態(例如啟用或禁用)和提交者都會被考慮在內。但是,這些都不會阻止表單的提交。一個簡單的方法是編寫一些 JavaScript 來處理可能中止進程的情況。
JavaScript 的最初用途之一實際上是為表單提供增強的功能。基本思想是在即將提交表單時收到事件通知。此時我們可以檢查所有值并中止該過程。當然,我們可以改進整個想法,以便在任何值發生變化時始終進行檢查。盡管如此,最終我們可能會根據我們最后的評估而中止提交。
var form = document.querySelector('form'); form.addEventListener('submit', function (ev) { // always abort! ev.preventDefault(); }, false);
登錄后復制
理論上進行實時驗證很容易。然而,指定的 DOM 事件的工作方式可能與直觀猜測的不同。例如,文本框的 change
事件僅在文本框失去焦點后才會觸發。當用戶單擊提交按鈕時可能會發生這種情況。因此,與驗證的交互被破壞并且感覺不活躍。
相反,使用 keyup
或 input
事件是有意義的。雖然前者是文本框的有效解決方案,但后者適用于所有輸入元素(如預期)。唯一的限制是它是隨 HTML5 引入的,某些較舊的瀏覽器可能不支持。
考慮到這一點,讓我們比較各個事件以查看執行順序。下面的測試代碼可以幫助我們。
var input = document.querySelector('input'); ['input', 'keyup', 'change'].forEach(function (eventName) { input.addEventListener(eventName, function (e) { console.log(eventName + ' event triggered'); }, false); });
登錄后復制
對于我們的測試 <input>
元素,當使用幾個字母進行探測時,我們會看到以下結果。最后我們使用 Tab 鍵顯式地移開焦點。
正如我們所看到的,順序設置為首先觸發 input
事件,然后觸發 keyup
。其實這是有道理的。首先我們需要 keydown
,然后該值可能會發生變化,從而導致 input
事件。最后我們釋放密鑰,這會產生一個 keyup
事件。值得強調的是,input
僅在值發生變化時才會觸發,而 keyup
與實際值變化無關。舉個例子,如果我們按箭頭鍵,我們只會看到 keyup
事件,而看不到 input
事件。
可以通過向所有表單字段添加事件偵聽器來對所有元素進行實時驗證。或者,我們只需要為表單添加一個用于 input
事件的事件偵聽器。盡管非常優雅,但這種方法有一個明顯的缺點。
考慮以下非常簡單的 HTML:
登錄后復制登錄后復制登錄后復制
我們使用 HTML5 form
屬性在其外部聲明 <form>
的一個字段。但是,input
事件正常工作,因為這些事件實際上會在 DOM 樹中冒泡。因此,外部場觸發的特定事件將不會被看到。
因此,最可靠的方法是獲取表單并迭代 elements
集合中給出的子項。這里收集所有分配的字段(image
輸入類型除外)。
約束驗證
約束驗證意味著我們能夠在 HTML 源代碼中指定約束,然后瀏覽器使用這些約束來檢查表單。有很多可能性。很多選項與輸入類型相關,不能隨意使用。在我們深入研究不同的驗證和實現怪癖之前,讓我們先簡要了解一下整體設計。
所選擇的 API 旨在使我們能夠進行快速檢查。我們可以探測當前實例是否能夠通過單個 API 調用進行約束驗證。
API也非常開放,我們可以查詢瀏覽器得到的結果,或者擴展瀏覽器的結果。偽接口Validation
也被其他接口繼承,不僅僅是HTMLInputElement
。
讓我們看一些示例代碼。在下面的代碼中,我們首先檢查表單驗證是否可行。如果是這樣,那么我們關心 type=date
字段的驗證結果。如果用戶選擇了有效日期,我們會檢查復選框的狀態。
var form = document.querySelector('form'); var date = document.querySelector('#birthday'); if (form.willValidate) { if (!date.validity.valid || checkbox.checked) checkbox.setCustomValidity(''); else checkbox.setCustomValidity('You need to agree to our terms.'); }
登錄后復制
這樣的條件邏輯(僅在某些情況下有效)不能單獨使用標記來實現。但我們可以很好地將自定義邏輯與集成功能結合起來。
HTML5 知道很多不同的輸入類型。但畢竟它們可以分為三類:
文字
數量
Date
從 value
屬性中看不到差異。這里我們總是得到 string
值。畢竟,該值將以文本形式提交。擁有這三個組的結果是針對某些類型的約束的不同行為。
以下約束幾乎總是以相同的方式起作用:
required
,如果 value
的長度為零,則導致 valueMissing
minlength
,如果字符串長度太短,會導致tooShort
maxlength
,如果字符串長度太長,會導致tooLong
當然,也有例外情況。例如,復選框會對 required
作出反應,要求進行 checked
。如果顏色選擇是 required
并且包含無效顏色,則顏色選擇將驗證為 valueMissing
。其他類型的反應類似。
其他可能的約束取決于輸入的具體類型。類型決定了如何處理該值。是否將其視為文本?它代表一個數字嗎?約束對其做出反應。
我們以date
輸入類型為例。如果設置了有效日期,如果限制為 required
,我們會得到一個 valueMissing
。此外,如果實際輸入了某些內容,則會設置 badInput
。但是,如果日期有效,我們可能會出現以下一個或多個驗證錯誤:
rangeUnderflow
,如果日期低于 min
屬性中指定的日期
rangeOverflow
,如果日期高于 max
屬性中指定的日期
stepMismatch
,如果日期不滿足提供的step
模式
最后一點相當有趣。這里我們必須處理一種機制,該機制減去基數(可以是默認基數,也可以是 min 屬性中提供的)并計算可以對步驟取模的數字。對于日期輸入類型,計算并不完全明顯。實際提供的日期類型是不同的。然而,從用戶的角度來看,結果是有意義的。
對于文本輸入,還有 pattern
屬性,它允許我們指定用于驗證的正則表達式。如果輸入類型支持此約束,則會在失敗時記錄 patternMismatch
。
結論
約束驗證使我們能夠為用戶(即使禁用了 JavaScript)提供有關當前表單狀態的即時反饋。我們不必為了顯示錯誤消息而浪費往返服務器的網絡帶寬。盡管如此,我們應該始終記住,表單提交通常是可以的。因此,在服務器端進行一些驗證是不可避免的。
約束驗證帶來的可能性幾乎是無限的。我們可以使用客戶端驗證來確保滿足正則表達式,考慮日期和數字的有效范圍,并選中某些復選框。我們還可以使用 JavaScript 擴展可用的檢查。
參考文獻
MDN:約束驗證
W3C:限制和表單提交
Raymond Camden:HTML5 表單驗證 – 約束驗證 API
Tomomi Imura – HTML5 輸入事件處理程序和用戶體驗
TJ VanToll – 約束驗證:Web 表單的本機客戶端驗證
以上就是掌握HTML5:約束驗證的詳細內容,更多請關注www.92cms.cn其它相關文章!