在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> </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>
下图是分别在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
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> </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也有限制和不足之处,体现在:
- 不能使用CSS去随意控制或改变其下拉建议列表中的项
- 不能控制datalist的位置
- 不能控制每次当用户输入多少个字符后,就出现下拉建议列表
- 不能控制大小写敏感,或当匹配什么样的字符就出现下拉建议列表
- 不能将其与服务端的数据源绑定
因此,目前来说,除非HTM L5关于datalist的相关标准有继续修订,或者各大浏览器厂商继续去改进,否则建议在实际的应用中,依然使用如jQuery Autocomplete等类似的插件去实现该功能。