使用ElementInternals創建自定義表單控件
Mar 26, 2025 am 09:44 AM長期以來,開發者一直渴望對錶單元素擁有更多控制權。雖然這說法略顯誇張,但創建或自定義表單組件多年來一直是前端網頁開發的聖杯。
自定義元素(例如<my-custom-element></my-custom-element>
)最強大的功能之一,自Google Chrome 77 版本起已悄然問世,並逐步應用於其他瀏覽器。 ElementInternals 標準是一套功能強大的功能集,其名稱卻十分低調。其功能包括參與表單以及圍繞輔助功能控件的API。
本文將探討如何創建自定義表單控件,集成約束驗證,介紹內部輔助功能的基礎知識,並展示如何將這些功能結合起來創建高度可移植的宏表單控件。
讓我們從創建一個與我們的設計系統匹配的簡單自定義元素開始。我們的元素將把所有樣式保存在shadow DOM 中,並確保一些基本的輔助功能。我們將使用來自Google Polymer 團隊的出色LitElement 庫作為我們的代碼示例,雖然您絕對不需要它,但它確實為編寫自定義元素提供了很好的抽象。
在這個示例中,我們創建了一個<rad-input></rad-input>
,它具有一些基本設計。我們還在表單中添加了第二個輸入,這是一個普通的HTML 輸入,並添加了默認值(因此您可以直接按提交並查看其工作方式)。
當我們單擊提交按鈕時,會發生幾件事。首先,調用提交事件的preventDefault
方法,在本例中,是為了確保我們的頁面不會重新加載。之後,我們創建一個FormData 對象,它使我們可以訪問有關表單的信息,我們用它來構造一個JSON 字符串並將其附加到<output></output>
元素。但是,請注意,添加到我們的輸出中的唯一值來自名為“basic”的元素。
這是因為我們的元素還不知道如何與表單交互,所以讓我們使用ElementInternals 實例設置我們的<rad-input></rad-input>
,以幫助它名副其實。首先,我們需要在元素的構造函數中調用我們的方法的attachInternals
方法,我們還將把ElementInternals polyfill 導入到我們的頁面中,以便與尚不支持該規範的瀏覽器一起使用。
attachInternals
方法返回一個新的元素內部實例,其中包含一些我們可以在我們的方法中使用的新API。為了讓我們的元素能夠利用這些API,我們需要添加一個返回true
的靜態formAssociated
getter。
1 2 3 4 5 6 7 8 9 10 |
|
讓我們來看看元素的internals
屬性中的一些API:
-
setFormValue(value: string|FormData|File, state?: any): void
— 此方法將在存在父表單的情況下設置元素在其父表單上的值。如果值為null,則元素將不參與表單提交過程。 -
form
— 如果存在,則為元素的父表單的引用。 -
setValidity(flags: Partial<validitystate> , message?: string, anchor?: HTMLElement): void</validitystate>
—setValidity
方法將幫助控制元素在表單中的有效性狀態。如果表單無效,則必須存在驗證消息。 -
willValidate
— 如果在提交表單時將評估元素,則為true。 -
validity
— 一個有效性對象,與附加到HTMLInputElement.prototype.validity
的API 和語義匹配。 -
validationMessage
— 如果使用setValidity
將控件設置為無效,則這是描述錯誤的消息。 -
checkValidity
— 如果元素有效,則返回true,否則返回false 並觸發元素上的無效事件。 -
reportValidity
— 與checkValidity
相同,如果事件未取消,則會向用戶報告問題。 -
labels
— 使用label[for]
屬性標記此元素的元素列表。 - 其他一些用於在元素上設置aria 信息的控件。
設置自定義元素的值
讓我們修改我們的<rad-input></rad-input>
以利用其中一些API:
在這裡,我們修改了元素的_onInput
方法以包含對this.internals.setFormValue
的調用。這告訴表單我們的元素想要使用其給定的名稱(在我們的HTML 中設置為屬性)在表單中註冊一個值。我們還添加了一個firstUpdated
方法(在不使用LitElement 時與connectedCallback
類似),該方法在元素完成渲染時將元素的值設置為空字符串。這是為了確保我們的元素始終具有表單的值(雖然不是必需的,但您可以通過傳入null 值來將元素從表單中排除)。
現在,當我們向輸入添加值並提交表單時,我們將在我們的<output></output>
元素中看到一個radInput
值。我們還可以看到我們的元素已添加到HTMLFormElement
的radInput
屬性中。但是,您可能已經註意到的一件事是,儘管我們的元素沒有值,它仍然允許表單提交。接下來,讓我們向我們的元素添加一些驗證。
添加約束驗證
為了設置字段的驗證,我們需要稍微修改一下元素,以便使用元素內部對像上的setValidity
方法。此方法將接受三個參數(如果元素無效,則僅需要第二個參數,第三個參數始終是可選的)。第一個參數是部分ValidityState
對象。如果任何標誌設置為true,則控件將被標記為無效。如果內置有效性鍵之一不滿足您的需求,則可以使用通用的customError
鍵。最後,如果控件有效,我們將傳入一個對象字面量({}) 來重置控件的有效性。
第二個參數是控件的有效性消息。如果控件無效,則需要此參數,如果控件有效,則不允許此參數。第三個參數是一個可選的驗證目標,如果表單提交無效或調用reportValidity
,則它將控制用戶的焦點。
我們將向我們的<rad-input></rad-input>
引入一個新方法來處理此邏輯:
1 2 3 4 5 6 7 8 9 10 11 |
|
此函數獲取控件的值和輸入。如果值等於空字符串並且元素被標記為必需,我們將調用internals.setValidity
並切換控件的有效性。現在我們需要做的就是在我們的firstUpdated
和_onInput
方法中調用此方法,我們就可以向我們的元素添加一些基本驗證了。
在未向我們的<rad-input></rad-input>
輸入值之前單擊提交按鈕,現在將在支持ElementInternals 規範的瀏覽器中顯示錯誤消息。不幸的是, polyfill 仍然不支持顯示驗證錯誤,因為在不支持的瀏覽器中沒有可靠的方法來觸發內置的驗證彈出窗口。
我們還通過使用我們的internals
對象向我們的示例添加了一些基本的輔助功能信息。我們向元素添加了一個附加屬性_required
,它將充當this.required
的代理以及required
的getter/setter。
1 2 3 4 5 6 7 8 |
|
通過將required
屬性傳遞給internals.ariaRequired
,我們正在提醒屏幕閱讀器我們的元素當前需要一個值。在polyfill 中,這是通過添加aria-required
屬性來完成的;但是,在支持的瀏覽器中,不會將屬性添加到元素中,因為該屬性是元素固有的。
創建微型表單
現在我們已經有了一個符合我們設計系統的有效輸入,我們可能想要開始將我們的元素組合成可以在多個應用程序中重複使用的模式。 ElementInternals 最引人注目的功能之一是setFormValue
方法不僅可以採用字符串和文件數據,還可以採用FormData 對象。因此,假設我們想要創建一個可能在多個組織中使用的通用地址表單,我們可以使用我們新創建的元素輕鬆做到這一點。
在這個示例中,我們在元素的shadow root 內創建了一個表單,我們在其中組合了四個<rad-input></rad-input>
元素來創建一個地址表單。這次我們沒有使用字符串調用setFormValue
,而是選擇傳遞表單的整個值。結果,我們的元素將其子表單內每個單獨元素的值傳遞到外部表單。
向此表單添加約束驗證將是一個相當簡單的過程,提供額外的樣式、行為和內容插槽也是如此。使用這些較新的API 最終允許開發人員在自定義元素中釋放大量潛力,並最終讓我們可以自由控制用戶體驗。
以上是使用ElementInternals創建自定義表單控件的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱門文章

熱門文章

熱門文章標籤

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)