HTML5 DataList实现输入框自动下拉提示

在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值相匹配。在各浏览器中运行上面的代码,马上可以看到效果了,如下图:

Datalist标签

 

在上图中,左上角的图为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的值,如下:

Datalist标签

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的效果图:

Datalist标签

Datalist标签

可惜的是,目前只有Chrome和IE 10支持datalist中使用range范围控件的做法。下面的这个表,很清晰说明了在各个浏览器中datalist和其他HTML 5控件搭配的情况:

Datalist标签

什么时候该使用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标签

要注意的是,客户端的这种验证不能取代服务端的验证,最佳的做法是依然在服务端进行合法性的校验。而且要注意的是在旧的浏览器中,是缺乏这种对于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标签

 

在上面的代码中,在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浏览器中运行的效果图:

Datalist标签

 

在上面的图中,可以看到,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等类似的插件去实现该功能。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

昵称 *