2014 年 9 月 2 日星期二

字母组合搜索 - 第二部分

本系列文章有三个部分,本文是第二部分,主要研究 DataTables 自定义搜索选项、API 和功能插件。第二部分扩展了 本系列文章第一部分 里面介绍的字母搜索控件,以便向最终用户快速提供搜索词的视觉反馈。此视觉信息将显示表中每个搜索选项的记录数。这通过 DataTables API 和使用 jQuery 显示信息元素来实现。

字母搜索

在浏览本文的代码之前,以下示例展示了我们将在此构建的内容。

姓名职位办公室年龄开始日期工资
Tiger Nixon系统架构师爱丁堡612011-04-25$320,800
Garrett Winters会计东京632011-07-25$170,750
Ashton Cox初级技术作者旧金山662009-01-12$86,000
Cedric Kelly高级 JavaScript 开发人员爱丁堡222012-03-29$433,060
Airi Satou会计东京332008-11-28$162,700
Brielle Williamson集成专家纽约612012-12-02$372,000
Herrod Chandler销售助理旧金山592012-08-06$137,500
Rhona Davidson集成专家东京552010-10-14$327,900
Colleen HurstJavaScript 开发人员旧金山392009-09-15$205,500
Sonya Frost软件工程师爱丁堡232008-12-13$103,600
Jena Gaines办公室经理伦敦302008-12-19$90,560
Quinn Flynn支持主管爱丁堡222013-03-03$342,000
Charde Marshall区域经理旧金山362008-10-16$470,600
Haley Kennedy高级营销设计师伦敦432012-12-18$313,500
Tatyana Fitzpatrick区域经理伦敦192010-03-17$385,750
Michael Silva营销设计师伦敦662012-11-27$198,500
Paul Byrd首席财务官 (CFO)纽约642010-06-09$725,000
Gloria Little系统管理员纽约592009-04-10$237,500
Bradley Greer软件工程师伦敦412012-10-13$132,000
Dai Rios人事主管爱丁堡352012-09-26$217,500
Jenette Caldwell开发主管纽约302011-09-03$345,000
Yuri Berry首席营销官 (CMO)纽约402009-06-25$675,000
Caesar Vance售前支持纽约212011-12-12$106,450
Doris Wilder销售助理悉尼232010-09-20$85,600
Angelica Ramos首席执行官 (CEO)伦敦472009-10-09$1,200,000
Gavin Joyce开发人员爱丁堡422010-12-22$92,575
Jennifer Chang区域经理新加坡282010-11-14$357,650
Brenden Wagner软件工程师旧金山282011-06-07$206,850
Fiona Green首席运营官 (COO)旧金山482010-03-11$850,000
Shou Itou区域营销东京202011-08-14$163,000
Michelle House集成专家悉尼372011-06-02$95,400
Suki Burks开发人员伦敦532009-10-22$114,500
Prescott Bartlett技术作者伦敦272011-05-07$145,000
Gavin Cortez团队负责人旧金山222008-10-26$235,500
Martena Mccray售后支持爱丁堡462011-03-09$324,050
Unity Butler营销设计师旧金山472009-12-09$85,675
Howard Hatfield办公室经理旧金山512008-12-16$164,500
Hope Fuentes秘书旧金山412010-02-12$109,850
Vivian Harrell财务经理旧金山622009-02-14$452,500
Timothy Mooney办公室经理伦敦372008-12-11$136,200
Jackson Bradshaw董事纽约652008-09-26$645,750
Olivia Liang支持工程师新加坡642011-02-03$234,500
Bruno Nash软件工程师伦敦382011-05-03$163,500
Sakura Yamamoto支持工程师东京372009-08-19$139,575
Thor Walton开发人员纽约612013-08-11$98,540
Finn Camacho支持工程师旧金山472009-07-07$87,500
Serge Baldwin数据协调员新加坡642012-04-09$138,575
Zenaida Frank软件工程师纽约632010-01-04$125,250
Zorita Serrano软件工程师旧金山562012-06-01$115,000
Jennifer Acosta初级 JavaScript 开发人员爱丁堡432013-02-01$75,650
Cara Stevens销售助理纽约462011-12-06$145,600
Hermione Butler区域经理伦敦472011-03-21$356,250
Lael Greer系统管理员伦敦212009-02-27$103,500
Jonas Alexander开发人员旧金山302010-07-14$86,500
Shad Decker区域经理爱丁堡512008-11-13$183,000
Michael BruceJavaScript 开发人员新加坡292011-06-27$183,000
Donna Snider客户支持纽约272011-01-25$112,000
姓名职位办公室年龄开始日期工资

鼠标控制

首先考虑如何向最终用户展示额外的搜索信息。正如您将在上面的示例中看到,当用户将鼠标移到字母上时,每个字母下方会显示一个带有数字的简单框。该数字表示搜索词有多少记录可用(下面讨论如何计算该数字)。

这主要是简单的 Javascript 和 jQuery,而不是特定于 DataTables 的,因此我不会在这里深入探讨,但我们基本上要做的就是将数字框的元素(info)附加到字母容器(alphabet,由第一部分的代码开发)。当鼠标进入搜索词元素(span 标签)时,信息元素会显示其内容和位置已更新,以便适用于搜索词。当移开鼠标时,信息元素也会被删除。

var info = $('<div class="alphabetInfo"></div>')
    .appendTo( alphabet );

alphabet
    .on( 'mouseenter', 'span', function () {
        info
            .css( {
                opacity: 1,
                left: $(this).position().left,
                width: $(this).width()
            } )
            .html( $(this).data('match-count') )
    } )
    .on( 'mouseleave', 'span', function () {
        info.css('opacity', 0);
    } );

数据属性

在上面的代码中,从数据属性中读取每个字母的搜索次数match-count - 例如,您可以考虑 HTML 如下所示

<div class="alphabet">
    <span data-match-count="57">None</span>
    <span data-match-count="3">A</span>
    <span data-match-count="4">B</span>
    <span data-match-count="5">C</span>
    ...
</div>

我们现在要做的就是当字母元素创建时,仅向它们添加数据属性。

要获取第一列中可用的数据,我们可以使用 DataTables column().data() 方法。将索引 0 传递给 column() 方法将检索第一列的数据,然后可以对其进行迭代,以统计每个字符作为数据集中第一个字母出现的次数。

为此,我们可以编写一个简单函数,对数据进行分箱,生成一个对象,其中包含每个字母的计数(对象中没有字母表示计数为零)


function bin ( data ) { var letter, bins = {}; for ( var i=0, ien=data.length ; i<ien ; i++ ) { letter = data[i].charAt(0).toUpperCase(); if ( bins[letter] ) { bins[letter]++; } else { bins[letter] = 1; } } return bins; }

结果对象可能如下所示

{
    "A": 3,
    "B": 4,
    "C": 5,
    ...
}

最后,我们使用从 column().data() 获取的数据调用该函数,然后在创建字母时使用分箱数据(参见第一部分

var columnData = table.column(0).data();
var bins = bin( columnData );

$('<span class="clear active"/>')
    .data( 'letter', '' )
    .data( 'match-count', columnData.length )
    .html( 'None' )
    .appendTo( alphabet );

for ( var i=0 ; i<26 ; i++ ) {
    var letter = String.fromCharCode( 65 + i );

    $('<span/>')
        .data( 'letter', letter )
        .data( 'match-count', bins[letter] || 0 )
        .addClass( ! bins[letter] ? 'empty' : '' )
        .html( letter )
        .appendTo( alphabet );
}

第二部分已完成代码

此页面顶部的示例完整代码,包括在 本系列第一部分 中开发的代码,如下所示

Javascript

var _alphabetSearch = '';

$.fn.dataTable.ext.search.push( function ( settings, searchData ) {
    if ( ! _alphabetSearch ) {
        return true;
    }

    if ( searchData[0].charAt(0) === _alphabetSearch ) {
        return true;
    }

    return false;
} );


function bin ( data ) {
    var letter, bins = {};

    for ( var i=0, ien=data.length ; i<ien ; i++ ) {
        letter = data[i].charAt(0).toUpperCase();

        if ( bins[letter] ) {
            bins[letter]++;
        }
        else {
            bins[letter] = 1;
        }
    }

    return bins;
}


$(document).ready(function() {
    var table = $('#example').DataTable();

    var alphabet = $('<div class="alphabet"/>').append( 'Search: ' );
    var columnData = table.column(0).data();
    var bins = bin( columnData );

    $('<span class="clear active"/>')
        .data( 'letter', '' )
        .data( 'match-count', columnData.length )
        .html( 'None' )
        .appendTo( alphabet );

    for ( var i=0 ; i<26 ; i++ ) {
        var letter = String.fromCharCode( 65 + i );

        $('<span/>')
            .data( 'letter', letter )
            .data( 'match-count', bins[letter] || 0 )
            .addClass( ! bins[letter] ? 'empty' : '' )
            .html( letter )
            .appendTo( alphabet );
    }

    alphabet.insertBefore( table.table().container() );

    alphabet.on( 'click', 'span', function () {
        alphabet.find( '.active' ).removeClass( 'active' );
        $(this).addClass( 'active' );

        _alphabetSearch = $(this).data('letter');
        table.draw();
    } );

    var info = $('<div class="alphabetInfo"></div>')
        .appendTo( alphabet );

    alphabet
        .on( 'mouseenter', 'span', function () {
            info
                .css( {
                    opacity: 1,
                    left: $(this).position().left,
                    width: $(this).width()
                } )
                .html( $(this).data('match-count') )
        } )
        .on( 'mouseleave', 'span', function () {
            info.css('opacity', 0);
        } );
} );

CSS

div.alphabet {
    position: relative;
    display: table;
    width: 100%;
    margin-bottom: 1em;
}

div.alphabet span {
    display: table-cell;
    color: #3174c7;
    cursor: pointer;
    text-align: center;
    width: 3.5%
}

div.alphabet span:hover {
    text-decoration: underline;
}

div.alphabet span.active {
    color: black;
}

div.alphabet span.empty {
    color: red;
}

div.alphabetInfo {
    display: block;
    position: absolute;
    background-color: #111;
    border-radius: 3px;
    color: white;
    top: 2em;
    height: 1.8em;
    padding-top: 0.4em;
    text-align: center;
    z-index: 1;
}

下一步

在本系列的结束部分,下周我们将使用此处开发的字母控制,并创建一个可重用的 DataTables 特性插件,允许该输入控件通过一行代码的任何 DataTable 使用。