2024 年 5 月 28 日,星期二
作者 艾伦·贾丁

输入分页插件

DataTables 2 引入了 功能 的概念,这些功能是与 layout 选项一起放置在表格周围的表格控件和信息组件。有几个内置功能,一些 扩展 添加了它们自己的功能,但我想利用这篇博文来介绍 DataTables 的一个新型功能插件,展示它的功能,并且详细说明为 DataTables 制作功能插件有多么容易。

这里要介绍的功能插件被称为 InputPaging,它提供一个控件,可以替换内置 paging 功能。它的功能包括

  • 向最终用户展示当前页码
  • 允许最终用户键入他们想要查看的页码
  • 可选的上一个/下一个按钮
  • 可选的第一个/最后一个按钮
  • 可选的总页数
  • 自动与 DataTable 的默认样式、Bootstrap 3/4/5、Bulma、Foundation、jQuery UI 和 FomanticUI 集成。

这是实际使用中的一个示例(InputPaging 控件位于表格的右下角)

姓名职位办公地点薪水
Tiger Nixon系统架构师爱丁堡$320,800
Garrett Winters会计师东京$170,750
Ashton Cox初级技术作者旧金山$86,000
Cedric Kelly高级 Javascript 开发者爱丁堡$433,060
Airi Satou会计师东京$162,700
Brielle Williamson集成专家纽约$372,000
Herrod Chandler销售助理旧金山$137,500
Rhona Davidson集成专家东京$327,900
Colleen HurstJavascript 开发者旧金山$205,500
Sonya Frost软件工程师爱丁堡$103,600
Jena Gaines办公室经理伦敦$90,560
Quinn Flynn支持主管爱丁堡$342,000
Charde Marshall区域总监旧金山$470,600
Haley Kennedy高级营销设计师伦敦$313,500
Tatyana Fitzpatrick区域总监伦敦$385,750
Michael Silva营销设计师伦敦$198,500
Paul Byrd首席财务官 (CFO)纽约$725,000
Gloria Little系统管理员纽约$237,500
Bradley Greer软件工程师伦敦$132,000
Dai Rios人事主管爱丁堡$217,500
Jenette Caldwell开发主管纽约$345,000
Yuri Berry首席营销官 (CMO)纽约$675,000
Caesar Vance售前支持纽约$106,450
Doris Wilder销售助理悉尼$85,600
Angelica Ramos首席执行官 (CEO)伦敦$1,200,000
Gavin Joyce开发者爱丁堡$92,575
Jennifer Chang区域总监新加坡$357,650
Brenden Wagner软件工程师旧金山$206,850
Fiona Green首席运营官 (COO)旧金山$850,000
Shou Itou区域营销东京$163,000
Michelle House集成专家悉尼$95,400
Suki Burks开发者伦敦$114,500
Prescott Bartlett技术作者伦敦$145,000
Gavin Cortez团队主管旧金山$235,500
Martena Mccray售后支持爱丁堡$324,050
Unity Butler营销设计师旧金山$85,675
Howard Hatfield办公室经理旧金山$164,500
Hope Fuentes秘书旧金山$109,850
Vivian Harrell财务主管旧金山$452,500
Timothy Mooney办公室经理伦敦$136,200
Jackson Bradshaw总监纽约$645,750
Olivia Liang支持工程师新加坡$234,500
Bruno Nash软件工程师伦敦$163,500
Sakura Yamamoto支持工程师东京$139,575
Thor Walton开发者纽约$98,540
Finn Camacho支持工程师旧金山$87,500
Serge Baldwin数据协调员新加坡$138,575
Zenaida Frank软件工程师纽约$125,250
Zorita Serrano软件工程师旧金山$115,000
Jennifer Acosta初级 JavaScript 开发人员爱丁堡$75,650
Cara Stevens销售助理纽约$145,600
Hermione Butler区域总监伦敦$356,250
Lael Greer系统管理员伦敦$103,500
Jonas Alexander开发者旧金山$86,500
Shad Decker区域总监爱丁堡$183,000
Michael BruceJavascript 开发者新加坡$183,000
Donna Snider客服纽约$112,000

用法

在详细介绍如何创建你自己的自定义功能插件之前,让我们探索如何使用 InputPaging 插件。

初始化

此示例的初始化非常简单

new DataTable('#inputPaging', {
    layout: {
        bottomEnd: 'inputPaging'
    }
});

请注意,此示例在新分页控件的底部使用新分页控件替换默认的 paging 控件。由于 layout 的工作原理,因此有可能在表格的上方和下方同时显示此控件,或者根据需要显示默认分页功能以及此功能!

来源

此插件的源代码在 DataTables 插件Git 仓库 中提供,并根据 MIT 许可证发布。可直接在你的页面中包含的分发文件在 DataTables CDN 上提供

CSS
JS

如果您正在使用打包器,则此插件在 npm 上可通过 datatables.net-feature-inputpaging 获得。要将它与 ES 模块一起使用,只需包含该软件包,它便会将自身注册为可用功能

import DataTable from 'datatables.net-dt';
import 'datatables.net-feature-inputpaging';

new DataTable('#example', {
    layout: {
        bottomEnd: 'inputPaging'
    }
});

此 StackBlitz 示例演示了如何在 Typescript + Vite 构建环境中使用此新插件。

选项

inputPaging 功能有三个选项

  • boolean firstLast控制是否显示第一个最后一个按钮
  • boolean previousNext控制是否显示上一个下一个按钮
  • boolean pageOf控制是否在输入当前页码后立即显示/ {pages}文本。

要设置选项,请在 layout 中使用 inputPaging 选项作为对象 - 例如

new DataTable('#example', {
    layout: {
        bottomEnd: {
            inputPaging: {
                pageOf: false
            }
        }
    }
});

创建功能插件

为 DataTables 创建功能插件非常简单 - 使用 DataTable.feature.register() 静态方法来使用 DataTables 注册你的功能。参考文档提供了方法的全部详细信息,但从本质上来说,它需要两个参数;功能名称(即如何引用 layout 中的功能),以及一个函数来创建对应功能的 DOM 元素和事件监听器。此函数应返回一个 DOM 节点,并传入两个参数 - DataTable 设置对象以及功能选项。

使用代码表示更容易理解

DataTable.feature.register('myToolbar', function (settings, opts) {
    // Define defaults
    let options = Object.assign({
        option1: false,
        option2: false
    }, opts);
 
    let container = document.createElement('div');
 
    // do something with the options and container
    // ...
 
    return container;
});

就是这样 - 你已经创建了 DataTables 功能插件!现在,让我们探讨如何构建分页控件。

DOM 元素

我们需要创建具有事件处理程序的多个 DOM 元素。对于此处讨论的部分,我们使用 DataTables 的默认样式处理,因此我们需要使用与 paging 控件相同的结构。这是我们想要的部分

<div class="dt-inputpaging dt-paging">
    <button class="dt-paging-button disabled">«</button>
    <button class="dt-paging-button disabled">‹</button>
    <div class="dt-paging-input">
        <input class="" type="text" inputmode="numeric" pattern="[0-9]*" style="width: 3ch;">
        <span class=""> / 6</span>
    </div>
    <button class="dt-paging-button">›</button>
    <button class="dt-paging-button">»</button>
</div>

在纯粹的 JS 中创建 DOM 节点总是会生成冗余的代码操作,因此我们为其创建一个辅助函数

/**
 * Create a new element
 *
 * @param tag Tag name
 * @param className Class to assign
 * @param text Text to show in the element
 * @param fn Click event handler
 * @returns Element
 */
function createElement(tag, className, text, fn) {
    var el = document.createElement(tag);

    if (className) {
        el.className = className;
    }

    if (text) {
        el.textContent = text;
    }

    if (fn) {
        el.addEventListener('click', fn);
    }

    return el;
}

然后创建“first”按钮可能类似于以下内容。请注意 i18n 用途,以便获取为第一个分页按钮定义的语言字符串。这确保了与 DataTable 的现有选项完全集成。此外,page() 在事件处理程序中用于触发页面更改。

let first = createElement(
    'button',
    'dt-paging',
    api.i18n('oPaginate.sFirst', '\u00AB'),
    () => api.page('first').draw(false)
);

每个按钮都创建,然后附加到父元素,它从特征创建函数返回。尽管使用了辅助函数,此代码仍然相当冗余,因此为了简洁,请参见 此处代码

Input 事件处理程序

这开始变得越来越有趣。只有数字值在 input 元素中具有任何相关性,因此我们可以使用事件处理程序来禁用终端用户输入非数字字符

// Block characters other than numbers
input.addEventListener('keypress', function (e) {
    if (e.charCode < 48 || e.charCode > 57) {
        e.preventDefault();
    }
});

我们还希望在终端用户在 input 中输入新数字时执行两个操作。第一个显而易见 - 我们需要使用 page() 将 DataTable 的显示页面更改为新数字(它具有内置修正功能,如果终端用户输入不存在的页面)。

第二个操作是调整 input 的宽度以适应内容。这对终端用户很有用,因为它允许他们看到完整的页码,而无需占用超出所需宽度的范围(这一点很重要,因为它允许表中有数百万行)。为此,我们使用带 ch 单元 的字符串中字符数,这是 0 的宽度(类似于 em,但适用于数字!)

// On new value, redraw the table
input.addEventListener('input', function () {
    if (input.value) {
        api.page(input.value - 1).draw(false);
    }

    // Auto adjust the width so the content is visible
    input.style.width = (input.value.length + 2) + 'ch';
});

DataTables 事件

最后,当 DataTable 绘制时,它会发出 draw 事件,在此事件中我们需要使用以下操作更新控件

  1. 可视化指示任何按钮是否已禁用(例如,当已在第一页时没有必要允许单击“First”按钮!)。这只需向上面创建的按钮添加或删除 disabled 类即可完成。page.info() 方法用于获取用于这些逻辑检查的数据。
  2. 接下来,如果外部操作更改了当前页面(例如,搜索将重置分页),我们需要将新值写入 input,以便终端用户可以看到他们所在的页面。
  3. 最后,总页码指示器需要更新,同样使用来自 page.info() 的信息。
api.on('draw', () => {
    let info = api.page.info();

    // Update the classes for the "jump" buttons to show what is available
    first.classList.toggle('disabled', info.page === 0);
    previous.classList.toggle('disabled', info.page === 0);
    next.classList.toggle('disabled', info.page === info.pages-1);
    last.classList.toggle('disabled', info.page === info.pages-1);

    // Set the new page value into the input box
    if (input.value !== info.page + 1) {
        input.value = info.page + 1;
    }

    // Show how many pages there are
    of.textContent = ' / ' + info.pages;
});

才刚刚开始

可以在 此处 找到上面构建的代码的完整列表。您可能已经注意到,此代码并未考虑 DataTables 支持的不同样式框架,例如 Bootstrap 和 Bulma。为了使此次讨论更加容易管理,我已经简化了用于全功能插件的实际代码!如果您感兴趣,请查看 此插件的源代码 - 关键是如何处理 DOM 结构,它因每个样式框架而异。

创建您自己的插件

如果您深受启发并创建了自己的 Feature 插件,请联系我们,并与社区分享!我很想看看您能做出什么。