2017 年 2 月 28 日,星期二

基于语言环境的排序

让我们刻板印象一下:开发人员的第一语言(在很多情况下,例如我本人,唯一语言)是英语,他们并不总是真正地意识到本地化问题。因为世界各地的用户都在使用 DataTables(68 种 DataTables 核心社区翻译),作为库开发人员,我非常清楚这点。

尽管 DataTables 提供了本地化其使用文本的选项,但我们还需要考虑表格中包含的数据。排序是此方面一直难以正确处理的领域之一,但幸运的是,浏览器中现在提供了新的 JavaScript API,我们可以每次绝对正确地针对语言环境进行排序。

此外,不要错误地以为这篇文章仅针对使用英语以外语言的开发人员 - Intl API 提供的排序选项为所有人提供了帮助!

标准化

Javascript 中的字符串排序通常通过简单比较 Unicode 代码点来进行,假设代码点较高的字符应排在代码点较低的字符之后。这当然很荒谬 - 它在很多情况下(尤其是 ASCII)可能有效,但并不适用于全球范围。

Javascript 1.2 引入了 localCompare,但它存在性能问题,而且浏览器和平台之间存在显著差异。

这让我们想到了 ECMA-402 标准 - Javascript 的国际化 API。此 API 基本上解决了 Javascript 中对本地化字符串进行排序的所有问题。它甚至超出了这些范围,并提供了一些真正有用的功能,例如控制大小写敏感度、忽略标点符号以及考虑字符串中的数字值。

使用 Intl API 进行排序

使用 Intl API 进行排序通过针对特定语言环境创建一个对照人来完成。这基本上是一个优化步骤,以确保我们仅执行语言和选项的一次设置。生成的对比人员对象有一个 compare 方法,我们可以使用它来对数据进行排序,就像使用 Array.prototype.sort 一样。例如

var collator = new Intl.Collator( 'fr' );

arrayToSort.sort( collator.compare );

就是这样!MDN 文档 详细介绍了可提供给对照人构造函数的选项,因此我们现在需要做的就是把它包装成一种可供 DataTables 使用的形式。

与 DataTables 的接口

DataTables 的字符串排序已实现为一个简单的代码点比较,如上所述,这不总是合适。因此,我们想要做的是用 Intl API 提供的字符串排序替换默认字符串排序。我们可以通过简单地覆盖 DataTables 中字符串排序的默认 ascdesc 方法(通过其标准的排序插件 API公开)来实现这一点。

        var collator = new window.Intl.Collator( ... );
        var types = $.fn.dataTable.ext.type;

        delete types.order['string-pre'];
        types.order['string-asc'] = collator.compare;
        types.order['string-desc'] = function ( a, b ) {
            return collator.compare( a, b ) * -1;
        };

这里有两个重要事项

  1. 删除 DataTables 使用的 string-pre 格式化函数。DataTables 中的默认排序不区分大小写,我们可能需要或可能不需要 Intl 排序。
  2. 与升序函数相比,降序函数更加有趣 - 我们需要反转校对器比较方法中的默认值 - 该方法只需将结果乘以 -1 即可完成。

现在,我们将它封装到一个函数中,使其可以像许多其他 DataTables 插件一样调用

$.fn.dataTable.ext.order.intl = function ( locales, options ) {
    if ( window.Intl ) {
        var collator = new window.Intl.Collator( locales, options );
        var types = $.fn.dataTable.ext.type;

        delete types.order['string-pre'];
        types.order['string-asc'] = collator.compare;
        types.order['string-desc'] = function ( a, b ) {
            return collator.compare( a, b ) * -1;
        };
    }
};

对于不支持 Intl API 的较旧浏览器,上述代码不起作用;用户将保留旧的默认代码点排序。当前所有浏览器都支持此 API,因此只有使用旧版浏览器的用户才能看不到好处。

用法

要立即在 DataTables 中实际使用 Intl 排序,我们需要执行上面定义的函数

$.fn.dataTable.ext.order.intl();

$('#myTable').DataTable();

上述将使用浏览器的默认语言环境。如果您想明确定义一个语言环境(这更有可能,因为您控制的是表中显示的数据,而不是用户的浏览器!),您可以使用第一个参数执行此操作(这与 Intl.Collator 完全相同)

$.fn.dataTable.ext.order.intl( 'fr' ); // French locale

第二个可选参数是选项,并让 Intl API 变得非常有趣,不仅适用于本地化,而且可以更好地控制整体排序。值得注意的选项有

  • sensitivity - 字符串之间应引起它们单独排序的不同之处(例如重音符号)。此项的值可以为 baseaccentcasevariant
  • ignorePuctuation - 标记以指示是否应忽略标点符号。
  • numeric - 允许按此方式对数字数据进行排序,而不是按字符串进行排序。
  • caseFirst - 选项允许大写或小写排在其它内容之前。这可以是 upperlowerfalse

我认为最感兴趣的一个或许是 numeric 选项,因为这在 DataTables 论坛中经常出现。如果您混合了数字和字符串数据,此选项允许按自然顺序对数据进行排序,而不是严格按字符串进行排序(例如 1, 2, 11 而不是 1, 11, 2)。

CDN

此插件可通过复制上述代码或直接从 DataTales CDN 中包含它来使用。

JS

未来发展

Intl 不仅提供排序选项,还提供筛选选项 - 例如如何处理重音符号在筛选时是另一个有趣而困难的话题。虽然此文章没有探讨此类选项,但这是我将在未来研究的内容。

我还计划为 Intl API 在 DataTables 的下一个主要版本中提供支持,而不是要求插件。

享受吧!