2014 年 10 月 2 日星期四

滑动子行

通过表中的特定记录显示相关信息的能力极大地简化了表中针对最终用户的显示,同时用户仍可访问详细信息视图中任意复杂的数据。为此,DataTables 内置了通过其 row().child() 一组 API 方法将子行显示为附件并附加到表中的父行。

这里有示例,展示了如何使用这些方法在子行中显示信息,但一个常见的需求是通过一点 jQuery 动画来增加子行的显示样式。

本篇博文将探讨如何轻松实现该效果,下表展示了最终结果。

姓名 职位 办公室 薪酬
姓名 职位 办公室 薪酬

起点

我们的起点将是 标准 DataTables 子行示例。让我们快速总结一下它的运作方式,方法是考虑以下代码

$('#example tbody').on('click', 'td.details-control', function () {
    var tr = $(this).closest('tr');
    var row = table.row( tr );

    if ( row.child.isShown() ) {
        // This row is already open - close it
        row.child.hide();
        tr.removeClass('shown');
    }
    else {
        // Open this row
        row.child( format(row.data()) ).show();
        tr.addClass('shown');
    }
} );
  • 第 1 行:将 click 事件监听器附加到表中具有类 details-control 的单元格中(使用 columns.className 初始化选项设置)。
  • 第 2 行:使用 jQuery 获取此行的 tr 节点引用
  • 第 3 行:使用 tr 元素,我们使用 DataTables API 获取该行的 API 对象,然后可用于子行操作。
  • 第 5 行:使用 row().child.isShown() 检查子行是否显示。
  • 第 6 至 8 行:如果当前可见,则使用 row().child.hide() 隐藏它。
  • 第 11 至 13 行:如果不可见,则使用 row().child.show() 和一个将呈现行中数据的格式化函数显示它(使用 row().data())。

你可以看到此处使用的 format() 方法只是展示了操作的示例,它可以根据你的需要返回所需显示的任何 HTML,无论其复杂程度如何。事实上,如需获取附加信息,它可以对服务器发起 Ajax 调用。

添加动画

为了添加动画,首先要考虑的是很容易通过 jQuery 的 $().slideDown()$().slideUp() 方法为其中包含的 div 元素设置动画,因此我们完全回避了对表格行高度设置动画这一较为复杂的操作。

在上述示例中,format() 函数将返回一个类似于下文的 HTML 字符串

<div class="slider">
    ... Data to be shown ...
</div>

我们在 CSS 中添加

div.slider {
    display: none;
}

这将确保在首次将元素添加到文档中时,该元素将处于隐藏状态,因此 jQuery 可以为其显示效果设置动画。

显示

现在,我们只需简单地使用 $().slideDown() 来为元素设置动画,通过添加一行代码来修改子行显示效果,使之类似于

// Open this row
row.child( format(row.data()) ).show();
tr.addClass('shown');

$('div.slider', row.child()).slideDown();

请注意,这里使用了 row().child() 来获取子行的引用,这样我们才能选择要设置动画效果的元素。

隐藏

设置动画效果,使子行关闭时的修改效果同样简单,我们使用了 $().slideUp() 及其在动画完成后提供的回调函数(此时我们明确应使用 row().child.hide() 来完全移除子行,而不是在动画之前或进行动画时移除子行)

// This row is already open - close it
$('div.slider', row.child()).slideUp( function () {
    row.child.hide();
    tr.removeClass('shown');
} );

更流畅的动画

当使用 默认 DataTables 样式表 和许多其他样式选项时,表格中的单元格将具有内边距。此内边距不属于 jQuery 在 div 元素上执行的动画效果的一部分,因此,当子行显示时,我们希望移除子行的内边距,而不是让它立即出现。这可以通过附加到子行容器单元格的类名来实现,而该类名可使用 row().child() 方法的第二个可选参数来指定

// Open this row
row.child( format(row.data()), 'no-padding' ).show();

添加额外的 CSS 规则

table.dataTable tbody td.no-padding {
    padding: 0;
}

这就是在 DataTables 中为子行添加滑动动画的全部内容!

完整代码

用于此示例的完整代码如下所示。

Javascript

/* Formatting function for row details - modify as you need */
function format ( d ) {
    // `d` is the original data object for the row
    return '<div class="slider">'+
        '<table cellpadding="5" cellspacing="0" border="0" style="padding-left:50px;">'+
            '<tr>'+
                '<td>Full name:</td>'+
                '<td>'+d.name+'</td>'+
            '</tr>'+
            '<tr>'+
                '<td>Extension number:</td>'+
                '<td>'+d.extn+'</td>'+
            '</tr>'+
            '<tr>'+
                '<td>Extra info:</td>'+
                '<td>And any further details here (images etc)...</td>'+
            '</tr>'+
        '</table>'+
    '</div>';
}

$(document).ready(function() {
    var table = $('#example').DataTable( {
        "ajax": "/examples/ajax/data/objects.txt",
        "columns": [
            {
                "class":          'details-control',
                "orderable":      false,
                "data":           null,
                "defaultContent": ''
            },
            { "data": "name" },
            { "data": "position" },
            { "data": "office" },
            { "data": "salary" }
        ],
        "order": [[1, 'asc']]
    } );
    
    // Add event listener for opening and closing details
    $('#example tbody').on('click', 'td.details-control', function () {
        var tr = $(this).closest('tr');
        var row = table.row( tr );

        if ( row.child.isShown() ) {
            // This row is already open - close it
            $('div.slider', row.child()).slideUp( function () {
                row.child.hide();
                tr.removeClass('shown');
            } );
        }
        else {
            // Open this row
            row.child( format(row.data()), 'no-padding' ).show();
            tr.addClass('shown');

            $('div.slider', row.child()).slideDown();
        }
    } );
} );

CSS

td.details-control {
    background: url('/examples/resources/details_open.png') no-repeat center center;
    cursor: pointer;
}

tr.shown td.details-control {
    background: url('/examples/resources/details_close.png') no-repeat center center;
}

div.slider {
    display: none;
}

table.dataTable tbody td.no-padding {
    padding: 0;
}