在本教程中,我們將深入探討HTML5中較少使用的<datalist>
元素。它能實現一個輕量級、易於訪問、跨瀏覽器的自動完成表單控件,無需JavaScript。
為什麼<select>
不夠好?
HTML5的<select>
控件在用戶需要從一個小範圍的選項中選擇時非常理想。但當遇到以下情況時,它們就顯得不那麼實用了:
- 選項非常多,例如國家或職稱
- 用戶想要輸入不在列表中的自定義選項
顯而易見的解決方案是自動完成控件。這允許用戶輸入幾個字符,從而限制可用的選項,以便更快地選擇。
<select>
在你開始輸入時會跳轉到正確的位置,但這並不總是顯而易見的。它不適用於所有設備(如觸摸屏),並且會在一秒或兩秒內重置。
開發者通常會轉向使用眾多的基於JavaScript的解決方案,但定制的自動完成控件並不總是必需的。HTML5的<datalist>
元素是輕量級的、易於訪問的,並且沒有JavaScript依賴。你可能聽說過它有bug或缺乏支持。在2021年,這並不真實,但確實存在瀏覽器的不一致性和注意事項。
<datalist>
快速入門
從包含超過200個選項的列表中選擇您的國家,是自動完成控制的理想候選。在HTML頁面中直接為每個國家定義一個包含子<option>
元素的<datalist>
:
<datalist id="countrydata">
<option>Afghanistan</option>
<option>Åland Islands</option>
<option>Albania</option>
<option>Algeria</option>
<option>American Samoa</option>
<option>Andorra</option>
<option>Angola</option>
<option>Anguilla</option>
<option>Antarctica</option>
...etc...
</datalist>
然後,datalist的id
可以被任何<input>
字段的list
屬性引用:
<label for="country">country</label>
<input type="text"
list="countrydata"
id="country" name="country"
size="50"
autocomplete="off" />
令人困惑的是,最好設置autocomplete="off"
。這確保用戶顯示的是<datalist>
中的值,而不是他們之前在瀏覽器中輸入的值。
結果:
這是Microsoft Edge中的默認渲染。其他應用程序實現了類似的功能,但外觀在不同平台和瀏覽器之間有所不同。
<option>
選項
使用<option>
的文本子標籤作為標籤是常見的:
<datalist id="mylist">
<option>label one</option>
<option>label two</option>
<option>label three</option>
</datalist>
使用value
屬性會產生相同的結果:
<datalist id="mylist">
<option value="label one" />
<option value="label two" />
<option value="label three" />
</datalist>
注意:在HTML5中,結束的/>
斜線是可選的,儘管它可能有助於防止編碼錯誤。
您還可以根據選定的標籤設置值,使用以下任一格式。
選項1:
<datalist id="mylist">
<option value="1">label one</option>
<option value="2">label two</option>
<option value="3">label three</option>
</datalist>
選項2:
<datalist id="mylist">
<option value="1" label="label one" />
<option value="2" label="label two" />
<option value="3" label="label three" />
</datalist>
在這兩種情況下,當選擇有效的選項時,輸入字段被設置為1
,2
或3
,但UI在不同的瀏覽器中有所不同:
- Chrome 顯示的列表包含值與標籤,選定選項後僅保留值。
- Firefox 顯示的列表僅含標籤,選定選項後則切換至值。
- Edge 僅顯示值。
以下 CodePen 範例展示了所有變化:
查看 Pen
HTML5 <datalist> 自動完成範例 by SitePoint (@SitePoint)
on CodePen.
實作方式將持續演進,但目前建議避免使用值與標籤,因為這可能會讓使用者感到困惑。(下方將討論一個解決方案.)
<datalist>
瀏覽器支援與回退方案
現代瀏覽器以及 Internet Explorer 10 和 11 均良好支援 <datalist>
元素:
雖有若干實作注意事項,但大多數情況下不影響使用。最壞的情況是欄位回退至標準文字輸入。
若必須支援 IE9 及以下版本,可採用一種回退模式,即當 <datalist>
失效時,結合標準 <select>
與文字輸入。以國家範例進行調整:
<label for="country">country</label>
<datalist id="countrydata">
<select name="countryselect">
<option></option>
<option>Afghanistan</option>
<option>Åland Islands</option>
<option>Albania</option>
<option>Algeria</option>
<option>American Samoa</option>
<option>Andorra</option>
<option>Angola</option>
<option>Anguilla</option>
<option>Antarctica</option>
...etc...
</select>
<label for="country">or other</label>
</datalist>
<input type="text"
id="country" name="country"
size="50"
list="countrydata"
autocomplete="off" />
查看SitePoint(@SitePoint)在CodePen上的Pen
HTML5 <datalist> 自動完成備用方案。
在現代瀏覽器中,<option>
元素成為<datalist>
的一部分,且“或其他”標籤不會顯示。它看起來與上述示例相同,但countryselect
表單值將設為空字符串。
在IE9及以下版本中,<select>
(非常長)和文本輸入字段均處於活動狀態:
在舊版IE中,兩個值均可輸入。您的應用程序必須:
- 決定哪個最有效,或
- 使用小型JavaScript函數在另一個改變時重置一個
在非文本控制項上使用<datalist>
基於Chrome的瀏覽器還可以將<datalist>
值應用於:
-
類型為
"date"
的輸入。用戶可以從定義為YYYY-MM-DD
值的一系列選項中選擇,但以本地格式呈現。 -
一種類型為
"color"
的輸入。使用者可以從定義為六位數十六進位值的顏色選項中選擇(三位數值不適用)。 -
一種類型為
"range"
的輸入。滑桿顯示刻度,但這並不限制可以輸入的值。
查看 Pen
HTML5 <datalist> 在其他輸入類型上的應用 由 SitePoint (@SitePoint)
在 CodePen 上。
<datalist>
CSS 樣式
如果你曾經苦於樣式化一個 <select>
框,… 那你算是輕鬆的!
一個 <input>
可以像平常一樣樣式化,但連結的 <datalist>
及其子元素 <option>
無法用 CSS 樣式化。列表的渲染完全由平台和瀏覽器決定。
I hope this situation improves, but for now, a solution is proposed at MDN which:
- 覆蓋了瀏覽器的默認行為
- 實際上將
<datalist>
視為<div>
,以便在 CSS 中進行樣式化 - 用 JavaScript 複製所有自動完成功能
I’ve enhanced it further and the code is available on GitHub. To use it, load the script anywhere in your HTML page as an ES6 module. The jsDelivr CDN URL can be used:
<script src="https://cdn.jsdelivr.net/npm/datalist-css/dist/datalist-css.min.js"></script>
或者,如果您使用打包工具,也可以通过 npm
安装:
npm install datalist-css
您的 <datalist>
元素必须采用 <option>value</option>
格式。例如:
<datalist id="mylist">
<option>label one</option>
<option>label two</option>
<option>label three</option>
</datalist>
注意:<option value="value" />
不可用,因为它会导致一个无法设置样式的空元素!
随后,可以通过添加 CSS 来设置部分或全部 <datalist>
和 <option>
元素的样式。例如:
datalist {
position: absolute;
max-height: 20em;
border: 0 none;
overflow-x: hidden;
overflow-y: auto;
}
datalist option {
font-size: 0.8em;
padding: 0.3em 1em;
background-color: #ccc;
cursor: pointer;
}
/* 激活选项样式 */
datalist option:hover, datalist option:focus {
color: #fff;
background-color: #036;
outline: 0 none;
}
示例:
查看 Pen
HTML5 <datalist> 自动完成 CSS 样式 由 SitePoint (@SitePoint)
在 CodePen 上。
样式化是可行的,但值得这么做吗?我怀疑不值得……
- 重新实现浏览器的标准键盘、鼠标和触摸控制,同时保持合理的可访问性,是困难的。MDN 示例不支持键盘事件,尽管我试图改进它,但在某些设备上仍然不可避免地会出现问题。
- 您依赖 200 行 JavaScript 来解决一个 CSS 问题。它最小化到 1.5kB,但如果您在同一页面上需要许多长的
<datalist>
元素,可能会引入性能问题。 - 若JavaScript為必要條件,使用一個更美觀、一致且經過實戰檢驗的JavaScript元件是否更為理想?
當JavaScript失效時,控制權會回退至未經樣式處理的標準HTML5 <datalist>
,但這僅為次要優勢。
建立一個Ajax增強的<datalist>
假設您的美術設計師能接受瀏覽器間的樣式差異,則可利用JavaScript來強化標準<datalist>
的功能。例如:
- 實作可選的驗證機制,僅接受
<datalist>
中的已知值。 - 從Ajax呼叫的搜尋API回傳資料中設定
<option>
元素。 - 當選擇某選項時,設定其他欄位值。例如,選擇「美國」會在一個隱藏輸入中設定「US」。
此代碼主要需重新定義<option>
元素,儘管有幾點編碼考量:
- Ajax API請求應僅在輸入字元達到最低數量後發生。
- 輸入事件應去彈跳處理。即,僅在用戶停止輸入至少半秒後才觸發Ajax呼叫。
- 查詢結果應予以快取,避免重複或解析相同呼叫。
- 應避免不必要的查詢。例如,輸入“un”會返回12個國家。無需再進行“unit”或“united”的Ajax呼叫,因為所有相關選項都已包含在最初的12個結果中。
I’ve created a standard Web Component for this, and the code is available on GitHub. The CodePen example below allows you to select a valid country after entering at least two characters. A music artist autocomplete then returns artists who originated in that country with names matching the search string:
查看Pen
HTML5 <datalist> with Ajax autocomplete by SitePoint (@SitePoint)
on CodePen.
- 國家查詢API由restcountries.eu提供。
- 音樂藝術家查詢API由musicbrainz.org提供。
若要在您的應用中使用,請在HTML頁面的任何位置以ES6模塊形式載入腳本。可使用jsDelivrCDN的URL:
<script src="https://cdn.jsdelivr.net/npm/datalist-ajax/dist/datalist-ajax.min.js"></script>
或者,如果您使用的是捆綁器,可以通過npm
安裝:
npm install datalist-ajax
創建一個帶有子<input>
的<auto-complete>
元素,作為數據輸入字段。例如,國家查詢使用此方法:
<label for="country">country lookup:</label>
<auto-complete
api="https://restcountries.eu/rest/v2/name/${country}?fields=name;alpha2Code;region"
resultname="name"
querymin="2"
optionmax="50"
valid="please select a valid country"
>
<input type="text" id="country" name="country" size="50" required />
</auto-complete>
<auto-complete>
元素屬性:
attribute | description |
---|---|
api |
the REST API URL (required) |
resultdata |
the name of the property containing a result array of objects in the returned API JSON (not required if only results are returned) |
resultname |
the name of the property in each result object which matches the search input and is used for datalist <option> elements (required) |
querymin |
the minimum number of characters to enter before a search is triggered (default: 1) |
inputdelay |
the minimum time to wait in milliseconds between keypresses before a search occurs (default debounce: 300) |
optionmax |
the maximum number of autocomplete options to show (default: 20) |
valid |
if set, this error message is shown when an invalid value is selected |
REST URL 必須至少包含一個 ${id}
識別符,該識別符由具有該 id
的 <input>
中設定的值替換。在上例中,api
URL 中的 ${country}
引用具有 "country"
id
的子 <input>
中的值。URL 通常使用子輸入,但頁面上任何其他欄位均可被引用。
restcountries.eu API 返回包含國家資料的單一物件或物件陣列。例如:
[
{
"name": "Cyprus",
"alpha2Code": "CY",
"region": "Europe"
},
{
"name": "Sao Tome and Principe",
"alpha2Code": "ST",
"region": "Africa"
},
{
"name": "Andorra",
"alpha2Code": "AD",
"region": "Europe"
}
]
resultdata
屬性無需設置,因為這是唯一返回的資料(沒有包裝物件)。resultname
屬性必須設置為 "name"
,因為該屬性用於填充 datalist <option>
元素。
選擇選項時,其他欄位可以自動填入。以下輸入接收了 "alpha2Code"
和 "region"
屬性資料,因為設置了 data-autofill
屬性:
<input data-autofill="alpha2Code" type="text" id="countrycode" name="countrycode" readonly />
<input data-autofill="region" type="text" id="region" name="region" readonly />
datalist-ajax
的工作原理
如果您不想閱讀 230 行代碼並保持魔法活躍,可以跳過此部分!
程式碼首先在 <auto-complete>
內建立一個新的 <datalist>
,並透過 list
屬性將其附加到子元素 <input>
上。一個 input
事件監聽器會監控 <input>
,當輸入的字符達到最小數量且用戶停止輸入時,便會調用 runQuery()
函數。
runQuery()
從表單中提取數據構建 API URL,並使用Fetch API進行 Ajax 呼叫。返回的 JSON 被解析後,會建立一個包含 <option>
元素的可重用 DOM 片段,並將其存入緩存中。
A datalistUpdate()
function is called, which updates the <datalist>
with the appropriate cached DOM fragment. Further calls to runQuery()
avoid Ajax calls if a query has already been cached or a previous query can be used.
A change
event handler also monitors the <input>
, which is triggered when focus is moved from the field and the value has been modified. The function checks that the value matches a known option and, if necessary, uses the Constraint Validation API to show the error message provided in the valid
attribute.
假設選擇了一個有效的選項,變更處理函數會將所有具有匹配 data-autofill
屬性的欄位填滿。保留對自動填充欄位的引用,以便在輸入無效選項後可以重置它們。
需要注意的是,並未使用影子 DOM。這確保了自動完成 <input>
(及 <datalist>
)元素可以通過 CSS 進行樣式設置,並在必要時被其他腳本訪問。
Dunkin’ <datalist>
HTML5 的 <datalist>
雖有局限性,但如果你需要一個簡單且與框架無關的自動完成欄位,它是非常理想的。缺乏 CSS 支援確實可惜,但瀏覽器供應商可能最終會解決這一疏忽。
本教程中展示的任何代碼和示例均可應用於您自己的項目中。
關於HTML5 Datalist輕量級自動完成控件的常見問題
HTML5的datalist元素是什麼,它是如何工作的?
HTML5的datalist元素是一個為輸入元素預定義的選項列表。它為表單元素提供了“自動完成”功能。datalist元素使用id屬性與特定的輸入元素關聯。輸入元素使用list屬性來識別datalist。在datalist內部,您可以定義代表輸入字段可用選項的option元素。
我如何使用HTML5的datalist進行自動完成?
要使用HTML5的datalist進行自動完成,您需要將datalist與輸入字段關聯。這通過在輸入字段中添加list屬性並將其值設置為datalist的id來完成。瀏覽器將根據用戶的輸入和datalist中定義的選項提供自動完成建議。
我可以在所有瀏覽器中使用HTML5的datalist元素嗎?
HTML5的datalist元素在大多數現代瀏覽器中都得到支持,包括Chrome、Firefox、Safari和Edge。但是,Internet Explorer 9及更早版本不支持它。您可以在Can I Use等網站上查看當前的瀏覽器兼容性。
我如何對HTML5的datalist選項進行樣式設置?
不幸的是,HTML5的datalist元素的樣式選項相當有限。下拉列表的外觀由瀏覽器控制,無法輕易通過CSS進行自定義。但是,您可以對與datalist關聯的輸入字段進行樣式設置。
我可以為單個輸入字段使用多個datalists嗎?
不,您無法將多個datalist與單一輸入欄位關聯。輸入欄位的list屬性僅能接受一個id,該id對應於一個datalist。若您需要提供多組選項,可能需使用JavaScript根據用戶輸入動態更改選項。
我能否將HTML5 datalist與其他輸入類型搭配使用?
可以,HTML5 datalist能與多種輸入類型配合使用,包括文字、搜尋、網址、電話、電子郵件、日期、月份、週、時間、日期時間本地、數字、範圍及顏色。然而,自動完成功能在某些輸入類型如範圍或顏色上可能無法如預期運作。
我能否將HTML5 datalist與select元素搭配使用?
不行,HTML5 datalist不能與select元素搭配使用。datalist旨在為輸入欄位提供自動完成建議,而select元素則提供下拉選單選項。若您需要下拉選單,應使用select元素。
我能否將JavaScript與HTML5 datalist搭配使用?
可以,您能使用JavaScript與HTML5 datalist來動態添加、移除或更改選項。但請注意,datalist不支援其選項上的事件如onchange或onclick。您需將事件監聽器添加到關聯的輸入欄位。
我能否將HTML5 datalist用於搜尋欄位?
可以,HTML5 datalist非常適合用於搜尋欄位。它能根據用戶輸入提供自動完成建議,進而提升用戶體驗。但您需手動填充datalist以包含可能的搜尋詞彙。
可以使用HTML5的datalist搭配textarea嗎?
不可以,HTML5的datalist無法與textarea搭配使用。datalist的設計是為了給輸入欄位提供自動完成建議,而不是textarea。如果你需要為textarea實現自動完成功能,你可能需要使用JavaScript庫或自行開發解決方案。
Source:
https://www.sitepoint.com/html5-datalist-autocomplete/