HTML5 Datalists:它们是什么以及何时使用






4.82/5 (6投票s)
在本文中,我将描述数据列表(datalists)是什么,何时适合使用它们,它们的局限性,以及如何处理不支持它们的浏览器。让我们开始吧。
自动补全是所有Web用户都熟悉的一种模式。当你进行搜索时,你的搜索引擎会建议术语。当你输入一封新电子邮件时,你的邮件客户端会建议收件人。然而,这种功能在没有相当多的JavaScript的情况下,Web开发者是无法实现的。HTML5的新元素之一,<datalist>
,将这种自动补全功能原生带到Web上。
在本文中,我将描述数据列表(datalists)是什么,何时适合使用它们,它们的局限性,以及如何处理不支持它们的浏览器。让我们开始吧。
创建数据列表
为了展示数据列表的工作原理,让我们从一个传统的文本输入开始
<label for="favorite_team">Favorite Team:</label>
<input type="text" name="team" id="favorite_team">
此字段要求用户提供他们最喜欢的运动队。默认情况下,用户不会获得任何额外的帮助来完成该字段。但通过使用数据列表,你可以提供一个选项列表供用户选择以完成该字段。为此,为每个建议定义一个带有option
元素的数据列表
<datalist>
<option>Detroit Lions</option>
<option>Detroit Pistons</option>
<option>Detroit Red Wings</option>
<option>Detroit Tigers</option>
<!-- etc... -->
</datalist>
要将数据列表与输入元素关联起来,请给输入元素一个list
属性,给数据列表一个匹配的id
属性。以下是一个例子
<label for="favorite_team">Favorite Team:</label>
<input type="text" name="team" id="favorite_team" list="team_list">
<datalist id="team_list">
<option>Detroit Lions</option>
<option>Detroit Pistons</option>
<option>Detroit Red Wings</option>
<option>Detroit Tigers</option>
<!-- etc... -->
</datalist>
请注意,输入元素的list
属性和数据列表的id
属性包含相同的值“team_list”。这提供了两者之间的链接。
就是这样。使数据列表工作不需要JavaScript。图1显示了用户在支持的浏览器中输入“D”后会看到的内容。
注意:Internet Explorer 10和Opera不需要用户输入字符即可看到建议,而Firefox和Chrome需要。
选项元素还可以有一个 value
属性。当用户可能不知道与给定选项关联的代码时,这很有用。考虑以下美国州输入
<label for="state">State:</label>
<input type="text" name="state" id="state" list="state_list">
<datalist id="state_list">
<option value="AL">Alabama</option>
<option value="AK">Alaska</option>
<option value="AZ">Arizona</option>
<option value="AR">Arkansas</option>
<!-- etc -->
</datalist>
在这里,用户将看到完整的州名列表,但当用户进行选择时,文本输入将填充州代码而不是完整名称。图2显示了一个示例。
autocomplete 属性
如果图1和图2中的数据列表看起来很熟悉,那是因为浏览器实现自动补全功能已经很久了。所有浏览器都有某种机制来存储用户的输入,以便以后用于自动补全。
作者可以使用autocomplete
属性来控制浏览器是否应该尝试根据之前的输入自动完成用户的数据。可能的值显示在以下示例中
<form>
<!--
If the autocomplete attribute is not specified, it inherits the value
of its parent form element. If not specified, the default value of the
form's autocomplete attribute is "on". Since neither this input nor its
form have the attribute specified, the "on" state will be used.
-->
<input type="text" name="firstName">
<!--
The "on" state indicates that the browser can remember the value for future
use as well as suggest previously stored values.
-->
<input type="text" name="address" autocomplete="on">
<!--
The "off" state tells the browser neither to store the value entered for
this input nor to suggest previously entered values. This should be
used if the data is sensitive or the value will never be reused.
-->
<input type="text" name="secret" autocomplete="off">
</form>
那么autocomplete
属性和数据列表有什么区别呢?autocomplete
属性告诉浏览器是否根据之前的输入向用户提供补全选项,以及是否存储输入的值以供将来补全。数据列表是作者提供的建议列表,无论之前的输入如何,它们总是显示。
一个需要注意的是,将autocomplete
属性设置为“off”会阻止数据列表在Opera中显示。以下是一个例子
<!--
This datalist will never display in Opera because the autocomplete attribute
is set to "off". It will display in all other supporting browsers.
-->
<input type="text" list="pets" autocomplete="off">
<datalist id="pets">
<option>Cat</option>
<option>Dog</option>
<option>Hamster</option>
<option>Turtle</option>
</datalist>
其他输入类型
虽然自动补全传统上与文本输入相关联,但数据列表也可以用于许多新的HTML5输入类型。考虑范围输入类型,它允许创建滑块表单元素。通过将其与数据列表结合使用,你可以向用户建议范围上的点。
例如,以下输入要求用户提供5到200美元之间的捐款。
<label for="donation">Donation Amount (USD):</label>
<input type="range" name="donation" id="donation" list="donation_list"
step="5" min="5" max="200">
<datalist id="donation_list">
<option>25</option>
<option>50</option>
<option>100</option>
<option>200</option>
</datalist>
图3和图4分别显示了Chrome 24和Internet Explorer 10中范围输入的显示。
你可以看到,每个浏览器都为每个提供的数据列表选项显示一个刻度线。此外,当用户将滑块移动到这些预定义值附近时,Chrome会将滑块吸附到这些值上。
不幸的是,目前只有Internet Explorer和Chrome支持范围输入上的数据列表。图5显示了现代浏览器中对常见输入类型上数据列表的支持。
何时使用数据列表
由于数据列表没有内置机制要求用户选择提供的选项,因此它们非常适合可以接受任何值的输入。前面提供的运动队示例就符合这一点。虽然数据列表建议了球队,但用户可以自由输入任何值。
相反,美国州示例未能通过此测试,因为用户必须提供一组有限的有效值。这种用例最好由select
元素处理,因为它强制进行选择。
一个例外是具有大量有效选择的输入。例如,考虑图6所示的传统国家/地区下拉列表。
此列表通过强迫用户筛选数百个选项来找到他们正在寻找的选项,从而阻碍了用户。自动补全功能非常适合此用例,因为用户可以通过输入一个或两个字符来快速筛选列表。
以下是国家/地区选择如何通过数据列表实现
<label for="country">Country:</label>
<input type="text" id="country" list="country_list">
<datalist id="country_list">
<option value="AF">Afghanistan</option>
<option value="AX">Åland Islands</option>
<option value="AL">Albania</option>
<option value="DZ">Algeria</option>
<!-- more -->
</datalist>
图7显示了用户输入“U”后会看到的内容。
强制输入值
虽然数据列表本身不允许你强制选择一个选项,但你可以轻松添加实现此目的的验证。例如,以下代码利用HTML5 约束验证 API 来添加此类验证
// Find all inputs on the DOM which are bound to a datalist via their list attribute. var inputs = document.querySelectorAll('input[list]'); for (var i = 0; i < inputs.length; i++) { // When the value of the input changes... inputs[i].addEventListener('change', function() { var optionFound = false, datalist = this.list; // Determine whether an option exists with the current value of the input. for (var j = 0; j < datalist.options.length; j++) { if (this.value == datalist.options[j].value) { optionFound = true; break; } } // use the setCustomValidity function of the Validation API // to provide an user feedback if the value does not exist in the datalist if (optionFound) { this.setCustomValidity(''); } else { this.setCustomValidity('Please select a valid value.'); } }); }
约束验证API在所有支持数据列表的浏览器中都已实现,因此如果数据列表有效,验证也应该有效。现在,当用户尝试提交带有数据列表的表单(并且他们尚未选择选项)时,他们将看到图8中所示的错误。
需要注意的是,约束验证API并不能消除服务器端验证的需要。使用旧版浏览器的用户将无法使用约束验证API,而且恶意用户可以轻易地规避客户端脚本。
虽然这种方法在现代浏览器中有效,但它向运行不支持的浏览器的用户呈现了一个无法使用的UI。用户被告知他们必须选择一个有效值,但如果他们的浏览器不支持数据列表,他们就无法看到选项。因此,如果你计划使用这种方法,提供一个在所有浏览器中都可用的UI至关重要。这可以通过检测浏览器是否支持数据列表,然后进行适当的polyfill来实现。
不支持的浏览器
截至本文撰写之时,文本输入的数据列表在Internet Explorer 10、Firefox 4+、Chrome 20+和Opera中受支持,这不幸地排除了大量用户。
与许多新的HTML5功能不同,对于大多数用例,在不支持数据列表的浏览器中无需额外工作。默认情况下,你提供的选项列表仅仅是建议;因此,使用不支持的浏览器的用户只需在没有任何建议的情况下填写文本字段即可。
然而,可以使用一些备用选项来为运行不支持的浏览器的用户提供更完整的体验。
回退到备用HTML内容
一种选项,由Jeremy Keith推广,是利用不支持数据列表元素的浏览器仍会向用户显示子元素的事实。以下显示了如何修改国家/地区数据列表示例并回退到使用<select>
<label for="country">Country:</label>
<datalist id="country_list">
<select name="country">
<option value="AF">Afghanistan</option>
<option value="AX">Åland Islands</option>
<option value="AL">Albania</option>
<option value="DZ">Algeria</option>
<option value="AS">American Samoa</option>
<!-- more -->
</select>
If other, please specify:
</datalist>
<input type="text" name="country" id="country" list="country_list">
支持数据列表的浏览器中呈现给用户的UI不会改变,但使用不支持的浏览器的用户现在会看到一个带有国家/地区选项的select元素和一个可以输入任何值的文本框。这显示在图9中。
Polyfilling(兼容性填充)
select回退没有提供的一个功能是数据列表原生提供的自动补全行为。如果这对你添加的数据列表很重要,第二个回退选项是polyfill数据列表的实现。
首先,你需要确定用户的浏览器是否支持数据列表。流行的特性检测库Modernizr提供了这样的测试,如下所示
if (Modernizr.input.list) {
//The browser supports the list attribute and datalists.
} else {
//The browser supports neither the list attribute nor datalists.
}
}
使用这种方法,你现在可以为不支持数据列表的浏览器用户polyfill数据列表实现。虽然有几种polyfill可用于数据列表,但我更喜欢使用jQuery UI的自动补全组件。以下代码显示了一个polyfill实现
var datalist,
listAttribute,
options = [];
// If the browser doesn't support the list attribute...
if (!Modernizr.input.list) {
// For each text input with a list attribute...
$('input[type="text"][list]').each(function() {
// Find the id of the datalist on the input
// Using this, find the datalist that corresponds to the input.
listAttribute = $(this).attr('list');
datalist = $('#' + listAttribute);
// If the input has a corresponding datalist element...
if (datalist.length > 0) {
options = [];
// Build up the list of options to pass to the autocomplete widget.
datalist.find('option').each(function() {
options.push({ label: this.innerHTML, value: this.value });
});
// Transform the input into a jQuery UI autocomplete widget.
$(this).autocomplete({ source: options });
}
});
// Remove all datalists from the DOM so they do not display.
$('datalist').remove();
}
图10显示了在Safari中使用jQuery UI自动补全polyfill的国家列表示例的显示。
你可能已经注意到,默认情况下,jQuery UI的自动补全组件匹配选项中任意位置的字符,而数据列表仅匹配字符串开头的选项。与原生数据列表不同,自动补全组件允许你自定义匹配选项的方式,随心所欲。
以下示例展示了如何构建一个仅匹配字符串开头选项的自动补全功能
<input type="text" id="autocomplete">
<script>
var options = ['Badger', 'Bat', 'Cat', 'Cheetah', 'Crocodile', 'Deer', 'Donkey',
'Elephant', 'Fish', 'Frog', 'Giraffe', 'Gorilla'];
$('#autocomplete').autocomplete({
// req will contain an object with a "term" property that contains the value
// currently in the text input. responseFn should be invoked with the options
// to display to the user.
source: function (req, responseFn) {
// Escape any RegExp meaningful characters such as ".", or "^" from the
// keyed term.
var term = $.ui.autocomplete.escapeRegex(req.term),
// '^' is the RegExp character to match at the beginning of the string.
// 'i' tells the RegExp to do a case insensitive match.
matcher = new RegExp('^' + term, 'i'),
// Loop over the options and selects only the ones that match the RegExp.
matches = $.grep(options, function (item) {
return matcher.test(item);
});
// Return the matched options.
responseFn(matches);
}
});
</script>
旧版Internet Explorer
要在旧版Internet Explorer中使数据列表元素的任何polyfill生效,你需要采取两个额外步骤。
选项元素
第一个是,Internet Explorer 9及更早版本都要求option
元素必须是select
元素的直接子元素。如果不是,这些版本将不识别它们,并且它们对polyfill将不可见。
幸运的是,这很容易解决。通过使用条件注释,你可以仅为这些版本的Internet Explorer在选项周围放置一个select
元素。请参考此示例
<datalist>
<!--[if IE]><select><!--<![endif]-->
<option>Apple</option>
<option>Banana</option>
<option>Cherry</option>
<!- etc -->
<!--[if IE]><select><!--<![endif]-->
</datalist>
Internet Explorer 9及更早版本现在将正确检测选项。Internet Explorer 10将不受影响,因为条件注释已从Internet Explorer 10的解析器中删除。所有其他浏览器也将忽略这些注释。
HTML5 Shiv
在 Internet Explorer 8 及更早版本中,未知元素不能包含子元素。因此,即使数据列表的选项元素位于 select 元素内,它们仍然不会被识别。
幸运的是,这个问题也有一个简单的解决方法。流行的HTML5 Shiv 库允许 Internet Explorer 6-8 未知的元素拥有子元素。此 shiv 默认包含在 Modernizr 中;只需确保在配置下载时选中“html5shiv”复选框。
数据列表的局限性
尽管数据列表非常适合向文本输入添加建议,但它们缺乏许多现代Web应用程序所需的自定义功能。例如,你无法使用数据列表执行以下操作
- 使用CSS改变其显示或其选项的显示。
- 控制列表的定位。
- 控制浏览器向用户显示结果之前输入的字符数。
- 控制什么是匹配(区分大小写,字符串开头匹配还是任意位置匹配等)。
- 将输入绑定到服务器端数据源。
这意味着如果你需要任何这些功能,你需要寻找更强大的自动补全解决方案。jQuery UI自动补全组件提供了实现所有这些功能及更多的能力。自动补全组件还支持所有浏览器回溯到Internet Explorer 7,而无需polyfill。有关自动补全组件的更多信息,请查看其演示和API文档。(自动补全组件仅处理基于文本的输入,因此它无法帮助你处理一些更专业的输入类型,如范围和颜色。)
总结
数据列表提供了一种快速、原生地向用户显示输入建议的方法。由于选项仅仅是建议,在许多情况下,无需为不支持的浏览器提供回退;这些浏览器的用户将 simply 看不到建议。
对于需要向所有用户提供功能性数据列表的情况,你可以检测支持情况并为缺乏支持的浏览器进行功能填充。
虽然数据列表非常适合提供建议,但它们提供的功能有限。如果你需要更强大的自动补全解决方案,jQuery UI 的自动补全组件是一个很好的起点。
本文是Internet Explorer团队HTML5技术系列的一部分。通过http://modern.IE提供的3个月免费BrowserStack跨浏览器测试,尝试本文中的概念。
关于作者
TJ VanToll是一位Web开发者和jQuery UI团队成员。他住在密歇根州兰辛,并在他的博客上撰写关于他使用jQuery、HTML 5、CSS以及其他令他感兴趣的事物的经验。他是双胞胎儿子的骄傲父亲,当他不在互联网上时,通常会发现他在追着他们转圈。在他的博客和Twitter-@tjvantoll上找到TJ。