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 都可以透過單行程式碼使用此輸入控制項。