在Web设计中,经常会用到如输入框的自动下拉提示,这将大大方便用户的输入。比如在Google中进行搜索的时候,就会出现下拉的智能提示列表选择框。这样的下拉列表框称为AutoComplete。在以前,如果要实现这样的功能,必须要求开发者使用一些Javascript的技巧或相关的框架进行ajax调用,需要一定的编程工作量。但随着HTML 5 的慢慢普及,开发者可以使用其中的新的DataList标记就能快速开发出十分漂亮的 AutoComplete组件的效果。本文将以实例的方式讲解HTML 5中DataList的使用和要注意的事项。
创建DataList
首先,我们看下传统的简单文本输入框是什么样子的,如下代码所示:
- <label for="favorite_team">Favorite Team:</label>
- <input type="text" name="team" id="favorite_team">
这个输入框中,用户必须手动在其中输入文字内容,并没有提示,而如果使用了HTML5 中的DataList,则可以允许用户从下拉列表中选择。一个最简单的DataList使用如下方式声明:
- <datalist>
- <option>Detroit Lions</option>
- <option>Detroit Pistons</option>
- <option>Detroit Red Wings</option>
- <option>Detroit Tigers</option>
- <!-- etc... -->
- </datalist>
在<datalist>标签中所包裹的就是可供用户选择的项了。
那么,如何将datalist和文本框进行绑定呢?使用如下的代码:
- <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>
- </datalist>
在上面的代码中,为文本输入框inputbox指定list属性,其值一定要和<datalist>中的id值相匹配。
在各浏览器中运行上面的代码,马上可以看到效果了,如下图:
在上图中,左上角的图为IE 10中的效果,右上角图为Firefox 18中的效果,左下角图为Chrome 24中的效果,右下角图为Opera 12的效果。
要注意的是IE 10和Opera 中,不需要用户必须输入一个字符才看到下拉的建议列表,而其他浏览器需要用户至少输入一个字符才能看到效果。
在Datlist中,同样可以为每一个下拉列表选项指定一个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>
- </datalist>
如果在option中一旦指定了value的值,则用户通过下拉列表选择后,文本框中显示的将会是value的值,如下图:
Autocomplete属性
下面讲解autocomplete属性。该属性可以设置为on或off,表示输入字段是否应该启用自动完成功能,如下代码所示:
- <form>
- <!--
- 如果设置了autocomplete属性,则将会继承父元表单元素中autocomplete的值得,
- 如果也没设置,则默认autocomplete为on,这里没进行任何设置,所以firstName的autocomplete属性为on
- -->
- <input type="text" name="firstName">
- <!--
- autocomplete设置为on,浏览器将记忆下用户每次输入的值
- -->
- <input type="text" name="address" autocomplete="on">
- <!--
- 设置为off,代表浏览器将不记忆用户在该文本框本次的输入,也不进行建议提醒
- -->
- <input type="text" name="secret" autocomplete="off">
- </form>
要注意的是,在opera浏览器中,如果设置autocomplete为off,则根本不显示datalist,而在其他浏览器中,是会显示datalist的,只不过失去自动建议提醒功能。
其他输入的属性
接下来,我们学习下datalist中其他的输入属性。在datalist的下拉列表提示框中,还可以支持其他类型的HTML 5标签,比如下面的代码,展示的是一个HTML 5的滑动数字条,在运行后,当鼠标每向右滑动时,会有对应的文字提示:
- 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>
#p#
下图是分别在Chrome 24和IE 10的效果图:
可惜的是,目前只有Chrome和IE 10支持datalist中使用range范围控件的做法。下面的这个表,很清晰说明了在各个浏览器中datalist和其他HTML 5控件搭配的情况:
什么时候该使用DataList?
要注意的是,使用这种下拉的智能提示框也要注意场合。比如在一些要选择不是太多的场景下,使用一般的下拉框其实就可以了。而如果在需要用户在很多数据中去选择,则可以建议使用Datalist下拉建议提示框,因为可以方便用户快速检索去选择。一个典型的场景就是对世界各个国家的选择,如下代码:
- <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>
限制datalist选择的值
有的场景下,我们要限制用户在下拉自动提示列表中所选择的值,而在IE 10中,有一系列专门为此新加入的API,具体可以参考:
http://msdn.microsoft.com/en-us/library/ie/hh673544(v=vs.85).aspx#dom_methods_input_val,下面的代码是一个使用的例子:
- / 找出所有绑定了datalist的input文本框
- var inputs = document.querySelectorAll('input[list]');
- for (var i = 0; i < inputs.length; i++) {
- //当输入文本框的值发生改变
- inputs[i].addEventListener('change', function() {
- var optionFound = false,
- datalist = this.list;
- //判断用户的输入是否存在于datalist的下拉列表框的数据项中
- for (var j = 0; j < datalist.options.length; j++) {
- if (this.value == datalist.options[j].value) {
- optionFound = true;
- break;
- }
- }
- 使用IE 10的Validation API中的setCustomValidity方法对是否存在合法的输入值进行前端的响应展示
- if (optionFound) {
- this.setCustomValidity('');
- } else {
- //如果用户的输入不在datalist列表中,前端显示相关错误信息
- this.setCustomValidity('Please select a valid value.');
- }
- });
- }
下图是在IE 10下,当用户输入的值不在下拉列表后,浏览器显示的错误提示信息如下:
要注意的是,客户端的这种验证不能取代服务端的验证,***的做法是依然在服务端进行合法性的校验。而且要注意的是在旧的浏览器中,是缺乏这种对于datalist的校验支持的,除非开发者另外进行编码进行校验。
如何应对不支持的浏览器
在写本文的时候,依然只有IE 10,Firefox 4+,Chrome 20+和Opera是支持datalist的,这意味着不少旧版本的浏览器的用户不能使用datalist的功能,但办法总是有的,下面分别介绍一些折衷的办法
1)datalist中嵌套使用传统的select下拉选择框
一个不错的解决方法,是在提供传统的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">
#p#
运行的效果为如下图所示:
在写本文的时候,依然只有IE 10,Firefox 4+,Chrome 20+和Opera是支持datalist的,这意味着不少旧版本的浏览器的用户不能使用datalist的功能,但办法总是有的,下面分别介绍一些折衷的办法:
1)datalist中嵌套使用传统的select下拉选择框
一个不错的解决方法,是在提供传统的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">
运行的效果为如下图所示:
意在上面的代码中,在datalist中嵌套了传统的select下拉文本框,而input文本框中依然绑定了datalist,这样的好处是,当在不支持datalist的浏览器中运行的时候会有上图的效果:一边是下拉选择,另外的是可以允许用户输入下拉列表中不存在的记录。而上面的代码如果在支持datalist的浏览器中运行,则是原来的只显示一个datalist的效果。
2)使用jquery ui中的autocomplete插件
还有一种方法就是判断当用户的浏览器是不支持datalist的话,则使用jquery ui中的autocomplete插件,代码如下:
- if (Modernizr.input.list) {
- //如果返回值为true,则证明浏览器支持datalist
- } else {
- //浏览器不支持datalist
- }
- }
使用jquery ui中的autocomplete插件的原因之一是因为其功能强大和简单易用,当然读者可以从下面的这个地址获得更多的候选方案:https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills,里面提供了很多在其他浏览器中用其他方法实现同样的HTML 5功能的方法。下面是具体的代码:
- var datalist,
- listAttribute,
- options = [];
- if (!Modernizr.input.list) {
- // 对每一个绑定datalist的输入文本框循环遍历
- $('input[type="text"][list]').each(function() {
- //找出对应的datalist
- listAttribute = $(this).attr('list');
- datalist = $('#' + listAttribute);
- if (datalist.length > 0) {
- options = [];
- //将datalist中的option值复制到jquery autocomplete控件中去
- datalist.find('option').each(function() {
- options.push({ label: this.innerHTML, value: this.value });
- });
- //将options和autocomplete控件重新绑定
- $(this).autocomplete({ source: options });
- }
- });
- // 移除所有的datalist不予以显示
- $('datalist').remove();
- }
上面代码的核心,就是找出所有的datalist中的值,然后循环逐一复制到传统的options数组中,然后将options和autocomplete控件重新绑定,,并不显示datalist,这样上面的代码就既可以在支持datalist的浏览器中运行,也可以在不支持datalist的浏览器中运行。
下图是在Safari浏览器中运行的效果图:
在上面的图中,可以看到,jquery autocomplete默认是下拉列出和用户输入字符匹配的所有单词,而原生的datalist只是列出首字母相同的单词。因此如果需要改动的话,可以按如下代码的方式,则可以让jquery autocomplete达到相同的效果。
- <input type="text" id="autocomplete">
- <script>
- var options = ['Badger', 'Bat', 'Cat', 'Cheetah', 'Crocodile', 'Deer', 'Donkey',
- 'Elephant', 'Fish', 'Frog', 'Giraffe', 'Gorilla'];
- $('#autocomplete').autocomplete({
- //req是用户输入的字符,responseFn是返回给用户的列表.
- source: function (req, responseFn) {
- var term = $.ui.autocomplete.escapeRegex(req.term),
- //使用正则表达式去匹配谁首字幕,'i'表示使用大小写敏感匹配
- matcher = new RegExp('^' + term, 'i'),
- //循环options并只选择满足的
- matches = $.grep(options, function (item) {
- return matcher.test(item);
- });
- responseFn(matches);
- }
- });
- </script>
要注意的是,针对旧版本的IE 浏览器(IE 9及之前的)必须要求options标签是一定要位于select标签的子标签中,这个可以通过使用如下代码的
条件注释去解决这个问题(参考:http://msdn.microsoft.com/library/ms537512.aspx)
- <datalist>
- <!--[if IE]><select><!--<![endif]-->
- <option>Apple</option>
- <option>Banana</option>
- <option>Cherry</option>
- <!- etc -->
- <!--[if IE]><select><!--<![endif]-->
- </datalist>
这样,IE 9及以前的IE 浏览器则不会对以上的语法报错了。
Datalist的限制
当然,Datalist也有限制和不足之处,体现在:
1)不能使用CSS去随意控制或改变其下拉建议列表中的项
2)不能控制datalist的位置
3) 不能控制每次当用户输入多少个字符后,就出现下拉建议列表
4)不能控制大小写敏感,或当匹配什么样的字符就出现下拉建议列表
5)不能将其与服务端的数据源绑定
因此,目前来说,除非HTM L5关于datalist的相关标准有继续修订,或者各大浏览器厂商继续去改进,否则建议在实际的应用中,依然使用如jQuery Autocomplete等类似的插件去实现该功能。