LuLu UI组件中文文档 » datalist数据列表

Fork Me

datalist数据列表

一、数据列表内置功能

  1. 原生autocomplete功能

    会记忆当前输入框经过表单提交过的值,并在下一次连续点击的时候出现autocomplete数据列表。

    使用示意:

    清除输入框数据

    <form>
        <p>
            <span class="ui-input ui-search-input">
                <input type="search" id="simple" name="search" results="5" required>
                <label class="ui-icon-search" for="submit">搜索</label>
            </span>
            <input type="submit" id="submit" class="clip">
    
            <a href="javascript:" id="clearStore">清除输入框数据</a>
        </p>
    </form>
    // 这个是让大家知道表单提交就会自动存储
    new Validate($('form').eq(0), function() {
        $.lightTip.success('搜索内容已经在本地存储');
    });
    var elSimple = $('#simple');
    // 其实就这一行代码
    var simpleList = new Datalist(elSimple);
    
    $('#clearStore').click(function() {
        simpleList.removeStore();
        $.lightTip.success(simpleList.value() + '已经从本地数据中清除');
    });

    本组件原本作用就是实现这里的「输入历史记录」功能的,后面的动态匹配什么的,都是附带的。

    采用和浏览器自身一样的机制实现,包括:

    1. <form>元素submit事件执行的时候,才会记录该数据;
    2. 数据查询key通过name属性值进行匹配;
    3. autocomplete="off"可以关闭自动提示和记忆功能。
    4. 操作交互也和浏览器内置交互一致,例如,输入框2此点击,显示对应列表,上下键选择,回车赋值等。

    换句话说,就是把浏览器内置的autocomplete功能美化了下,所谓UI组件,本来就应该关注UI.

    当选择列表内容之后,默认会触发<input>输入框的change事件,基本上做到与业务事件的分离。

  2. 基于ajax动态返回数据的autocomplate功能

    <form action="datalist.html">
        <input class="ui-input" type="search" id="ajaxSearch" name="key" size="30" placeholder="输入字母">
        <label class="ui-button ui-button-primary" for="sSubmit">搜索</label>
        <input type="submit" id="sSubmit" class="clip">
    </form>
    new Datalist($('#ajaxSearch'), {
        data: {
            url: '/search',
            data: {
                userid: 1
            },
            success: function() {
                console.log('success callback success!');
            }
        }
    });

    这里的datalist数据由后端提供,前端发送搜索内容给后端,通过返回数据展现。

    data参数设置为Ajax请求对象(和jQuery $.ajax方法参数一致),其中url属性是必须的。

    一旦Ajax datalist初始化,会给输入框添加autocomplete="off"关闭浏览器内置的自动完成。

    默认是'json'类型数据。

    其中,请求的data参数和success参数和组件内部的参数设置合并。其中:

    1. data参数,都懂的,就是我们要把搜索文字动态发送过去,因此,需要内置。查询关键字就是<input>元素的name属性值,如果缺省,使用字符k代替;
    2. 组件内的success作用是呈现列表,如果你有其他成功回调处理,直接设置,不冲突,两者走的合并策略。

    然而,我们实际使用的时候不会像上面这么简单,因此不同项目不同开发返回的数据格式和后台接口都是不一样的。本Datalist组件支持的返回数据结构结构如下:

    {
        data: []
    }

    也就是前后端接口是data,这个其实比较好满足,关键是data后面属性值不一定是Datalist需要的数组格式,可能这样:

    {
        data: {
            pageInfo: {},
            data: []
        }
    }

    也就是数据列表是data.data,此时,我们可以使用filter参数处理,filter参数是个专门对数据进行过滤和处理的方法,例如,我们可以这样:

    new Datalist($('#ajaxSearch'), {
        data: {
            url: '/cgi/search.php',
            filter: function(data) {
                return data.data;
            }
        }
    });

    如果更进一步,data.data数组中的对象属性名不是value(必须),也不是label(可缺省),而是其它,例如:

    {
        data: {
            pageInfo: {},
            data: [{
                content: 'aaaaa'
            }, {
                content: 'bbbbb'
            }]
        }
    }

    此时,同样在filter方法中进行处理,返回Datalist需要的数组格式就可以了:

    new Datalist($('#ajaxSearch'), {
        data: {
            url: '/cgi/search.html',
            filter: function(data) {
                return $.map(data.data, function (obj) {
                    return {
                        value: obj.content
                    }
                });
            }
        }
    });
  3. 静态数据的动态匹配

    例如下面的邮箱自动补全功能:

    邮箱:

    邮箱:<input type="email" id="emailMatch" class="ui-input" size="30">
    new Datalist($('#emailMatch'), {
        data: ['qq.com', 'gmail.com', '126.com', '163.com'],
        filter: function(data, value) {
            var value = value.split('@')[0];
    
            return $.map(data, function(domain) {
                return {
                    value: value + '@' + domain
                };
            });
        }
    });
  4. 带滚动条的测试

    选择工作项:连续点击2次输入框
    var manyList = new Datalist($('#manyList'), {
        data: [{
            label: 'top1',
            value: '企点服务迭代三(4月6日~5月5日)'
        }, ... , {
            label: 'top11',
            value: '视觉体验迭代'
        }],
        max: 'auto'
    });
    // 设置为'auto'则双击空输入框时候也会出现列表
    manyList.params.data = 'auto';

二、语法和API参数

  • 语法

    new Datalist(trigger, options);

    或者链式调用:

    trigger.datalist(options);
  • API参数

    trigger默认就是指的我们的输入框,options为可选参数,具体见下表:

    参数名称 支持类型 默认值 释义
    data String|Array|
    Function|Object
    'auto' 列表的数据,默认auto表示从本地获取;
    还可以是静态数组,数组内为类似下面结构的对象:{
      label: '', // 可选,右侧小文字
      value: '' // 必须
    }
    也可以是Function动态获取数据内容;
    也可以是Ajax请求数据对象。
    max String|Number 8 最多显示的列表项条数,默认8条。使用关键字'auto'表示数据没有限制。可以使用HTML原生的类目个数属性results重置显示的条目数,例如results="5"最多显示5条列表数据。
    width String|Number 'auto' 列表的宽度,默认'auto'表示和trigger触发元素的outerWidth宽度一致。
    container Object $(document.body) jQuery包装器对象,指装载列表的容器,默认直插页面。
    filter Function function(data, value) {
      /* 首字符匹配过滤 */
    }
    对现有的数据进行重新过滤或者重新组装,只要返回需要的数组就好了,数组格式和细节和data参数一致。其中,this上下文指当前实例元素,支持2个参数,data为需要处理的数据(也是数组格式),value是输入框xss过滤后的值。
    trigger String|Array ['change'] 当选值时候触发的文本框的事件类型。
    onShow Function $.noop 列表显示时候触发的回调。this上下文指当前实例元素,支持2个参数,分别是触发元素trigger和列表面板元素target.
    onHide Function $.noop 列表隐藏时候触发的回调。this上下文指当前实例元素,支持2个参数,分别是触发元素trigger和列表面板元素target.
  • 关于实例对象

    假设我们有一个名为myDatalist的实例对象,代码为:

    var myDatalist = new Datalist(el);

    myDatalist对象暴露了如下属性和方法:

    {
        el: {
            // 输入框元素
            trigger: $(),
            // append列表的容器
            container: $(),
            // 列表面板元素
            target: $()
        },
        callback: {
            trigger: [],
            // 这个根据params.data生成的获得实时列表数据的方法,真正的数据源
            data: $.noop,
            filter: $.noop,
            show: $.noop,
            hide: $.noop
        },
        params: {
            width: params.width,
            max: params.max,
            // 初始化完成,就作为标志量使用(如设为'auto'就能focus显示列表)
            data: params.data,
            index: -1
        },
        bool: {
            modern: true|false
        },
        display: true|false,
        // 当前列表所使用的数据
        data: [],
        // 存储本地输入框的值
        store: $.noop,
        // 清除本地记录,支持1个可选的value参数,有3种逻辑:
           1. 字符串内容,表示移除本地该值数据(如果有)
           2. true, 表示清空本地对应该存储
           3. undefined, 表示使用trigger输入框的value值作为移除对象
        removeStore: $.noop,
        // 根据当前value值刷新列表,支持一个可选的data参数,表示使用指定数据进行列表呈现。
        refresh: $.noop,
        create: $.noop,
        // 支持一个可选参数,类似jQuery $().val(value)方法,有参数表示赋值,没有表示获取值。
           这里返回的是输入框xss过滤后的数值。
        value: $.noop,
        events: $.noop,
        // 列表定位
        position: $.noop,
        // 显示列表
        show: $.noop,
        // 隐藏列表
        hide: $.noop
    }

    如果使用的是jQuery链式调用语法,则实例对象可以这么获取。

    el.datalist();
    var myDatalist = el.data('datalist');

    也就是实例对象通过data方法存储在了jQuery元素上。

三、基于数据列表拓展的案例

  1. 带搜索的下拉列表

    使用CSS重置了一些样式,例如,绝对定位就不要了,阴影效果也不要了:

    .datalist_container .ui-datalist {
        display: block!important;
        position: static!important;
    }
    .datalist_container .ui-datalist-datalist {
        margin-top: 10px;
        border: 1px solid #d0d0d5;
        box-shadow: none;
    }

    这里的按钮HTML直接取自Select组件UI,因为我懒:

    <div class="ui-select" style="width:300px;">
        <a href="javascript:" id="select" class="ui-select-button"><span class="ui-select-text">企点服务迭代三(4月6日~5月5日)</span><i class="ui-select-icon"></i></a>
    </div>

    然后是JS代码,使用了组件体系中的Drop.js,而这里的Datalist则静态处理:

    // 这里展开浮层的HTML结构,有个搜索框还有一个容器
    var htmlDrop = '<div class="ui-droplist-x">\
        <div class="p10">\
            <div class="ui-input ui-search-input ui-search-right">
                <input type="search">
                <label class="ui-icon-search">搜索</label>
            </div>\
            <div id="cont" class="datalist_container"></div>\
        </div>\
    </div>';
    
    var trigger = $('#select'), target = $(htmlDrop);
    // 面板的宽度和按钮一样宽
    target.width(trigger.outerWidth());
    
    // 使用Drop.js
    new Drop(trigger, target, {
        eventType: 'click',
        onShow: function(trigger, target) {
            var drop = this;
            var input = target.find('input'), span = trigger.find('span');
            if (!this.datalist) {
                // 只构造一次
                var datalist = new Datalist(input, {
                    data: data,
                    width: 280,
                    container: target.find('#cont'),
                    max: 'auto'
                });
    
                datalist.params.data = 'auto';
                datalist.refresh();
    
                // 事件
                datalist.el.target.delegate('li', 'click', function() {
                    span.html($(this).attr('value'));
                    drop.hide();
                });
    
                input.on('input', function() {
                    if (this.value == '') {
                        // 空值显示完整列表
                        datalist.refresh();
                    }
                }).on('keydown', function(event) {
                    if (event.keyCode == 13) {
                        // 回车选中
                        var selected = datalist.el.target.find('.selected');
                        if (selected.length) {
                           span.html(selected.attr('value'));
                           drop.hide();
                        }
                    }
                });
    
                this.datalist = datalist;
            } else {
                input.val('');
                this.datalist.refresh();
            }
    
            // 高亮选中的元素
            this.datalist.el.target.find('li').each(function() {
                if ($(this).attr('value') == span.html()) {
                    $(this).addClass('selected');
                }
            });
        }
    });

    上面代码更多示意目的,未严格验证(如IE8不支持input事件),大家如果有需求,可以整到项目的一些拓展组件库里面去。

    上面的搜索功能采用的是默认的从前往后字符严格匹配,如果想支持首字母查询,或是模糊查询,使用filter参数,把filter设置为自己想要的查询方法即可!

四、作为插件使用

引入CSS:

<link rel="stylesheet" href="//qidian.gtimg.com/lulu/theme/peak/css/common/ui/Datalist.css">

引入JS(jquery文件略):

<script src="//qidian.gtimg.com/c/=/lulu/theme/peak/js/common/ui/Follow.js,/lulu/theme/peak/js/common/ui/Datalist.js"></script>

单独使用Demo演示

Fork Me 返回顶部