2017 年 7 月 24 日星期一

深度链接到 DataTables

论坛中经常出现的一个问题是:"如何对一个 DataTable 进行深度链接?"通常在搜索引擎优化 (SEO) 语境下,您需要确保表格中的所有数据均可被索引,但它也可用于您希望显示带有特定预设搜索词的表格的应用中。

通常此类问题的答案是使用 初始化参数 来设置所需的选项,通过 search string,但这通常是个很常见的事情,所以泛化它是有道理的。为了达到这个目标,以下我提供一个简短的脚本,可用它从搜索字符串中提取参数,并使用它们填充一个 DataTable。

让我们先在实际应用中看看——点击以下链接,观察演示表格的行为

姓名职位办公室年龄开始日期工资
Tiger NixonSystem ArchitectEdinburgh612011-04-25$320,800
Garrett WintersAccountantTokyo632011-07-25$170,750
Ashton CoxJunior Technical AuthorSan Francisco662009-01-12$86,000
Cedric KellySenior Javascript DeveloperEdinburgh222012-03-29$433,060
Airi SatouAccountantTokyo332008-11-28$162,700
Brielle WilliamsonIntegration SpecialistNew York612012-12-02$372,000
Herrod ChandlerSales AssistantSan Francisco592012-08-06$137,500
Rhona DavidsonIntegration SpecialistTokyo552010-10-14$327,900
Colleen HurstJavascript DeveloperSan Francisco392009-09-15$205,500
Sonya FrostSoftware EngineerEdinburgh232008-12-13$103,600
Jena GainesOffice ManagerLondon302008-12-19$90,560
Quinn FlynnSupport LeadEdinburgh222013-03-03$342,000
Charde MarshallRegional DirectorSan Francisco362008-10-16$470,600
Haley KennedySenior Marketing DesignerLondon432012-12-18$313,500
Tatyana FitzpatrickRegional DirectorLondon192010-03-17$385,750
Michael SilvaMarketing DesignerLondon662012-11-27$198,500
Paul ByrdChief Financial Officer (CFO)New York642010-06-09$725,000
Gloria LittleSystems AdministratorNew York592009-04-10$237,500
Bradley GreerSoftware EngineerLondon412012-10-13$132,000
Dai RiosPersonnel LeadEdinburgh352012-09-26$217,500
Jenette CaldwellDevelopment LeadNew York302011-09-03$345,000
Yuri BerryChief Marketing Officer (CMO)New York402009-06-25$675,000
Caesar VancePre-Sales SupportNew York212011-12-12$106,450
Doris WilderSales AssistantSydney232010-09-20$85,600
Angelica RamosChief Executive Officer (CEO)London472009-10-09$1,200,000
Gavin JoyceDeveloperEdinburgh422010-12-22$92,575
Jennifer ChangRegional DirectorSingapore282010-11-14$357,650
Brenden WagnerSoftware EngineerSan Francisco282011-06-07$206,850
Fiona GreenChief Operating Officer (COO)San Francisco482010-03-11$850,000
Shou ItouRegional MarketingTokyo202011-08-14$163,000
Michelle HouseIntegration SpecialistSydney372011-06-02$95,400
Suki BurksDeveloperLondon532009-10-22$114,500
Prescott BartlettTechnical AuthorLondon272011-05-07$145,000
Gavin CortezTeam LeaderSan Francisco222008-10-26$235,500
Martena MccrayPost-Sales supportEdinburgh462011-03-09$324,050
Unity ButlerMarketing DesignerSan Francisco472009-12-09$85,675
Howard HatfieldOffice ManagerSan Francisco512008-12-16$164,500
Hope FuentesSecretarySan Francisco412010-02-12$109,850
Vivian HarrellFinancial ControllerSan Francisco622009-02-14$452,500
Timothy MooneyOffice ManagerLondon372008-12-11$136,200
Jackson BradshawDirectorNew York652008-09-26$645,750
Olivia LiangSupport EngineerSingapore642011-02-03$234,500
Bruno NashSoftware EngineerLondon382011-05-03$163,500
Sakura YamamotoSupport EngineerTokyo372009-08-19$139,575
Thor WaltonDeveloperNew York612013-08-11$98,540
Finn CamachoSupport EngineerSan Francisco472009-07-07$87,500
Serge BaldwinData CoordinatorSingapore642012-04-09$138,575
Zenaida FrankSoftware EngineerNew York632010-01-04$125,250
Zorita SerranoSoftware EngineerSan Francisco562012-06-01$115,000
Jennifer Acosta初级 Javascript 开发人员Edinburgh432013-02-01$75,650
Cara StevensSales AssistantNew York462011-12-06$145,600
Hermione ButlerRegional DirectorLondon472011-03-21$356,250
Lael GreerSystems AdministratorLondon212009-02-27$103,500
Jonas AlexanderDeveloperSan Francisco302010-07-14$86,500
Shad DeckerRegional DirectorEdinburgh512008-11-13$183,000
Michael BruceJavascript DeveloperSingapore292011-06-27$183,000
Donna Snider客户支持New York272011-01-25$112,000
姓名职位办公室年龄开始日期工资

此示例的代码很简单

$('#myTable').DataTable( $.fn.dataTable.ext.deepLink( [
    'search.search', 'order', 'displayStart'
] ) );

还需要在您的页面中包含深度链接脚本

JS

用法

在您自己的页面中使用此脚本的关键元素是 $.fn.dataTable.ext.deepLink 函数。它带有一个参数:允许搜索参数指定的选项的数组,并返回一个包含这些初始化选项的对象,可以像上面一样直接传递给 DataTable。

采用白名单方法来限制出于安全考虑可以使用哪些选项。例如,您不太可能希望允许用户修改 ajaxserverSidescrollY 参数。如果给出的参数未在白名单中,将忽略该参数。话虽如此,如果您在一个希望使用任何和所有参数的环境中使用应用程序,则可以将 all 指定为该函数的唯一参数,这将允许所有参数。

一个简单的示例:允许从搜索字符串设置 search.search 参数

$('#myTable').DataTable( $.fn.dataTable.ext.deepLink( [
    'search.search'
] );

扩展默认值

由于 deepLink() 函数只返回一个对象,因此您可以提供可选地可以被搜索字符串覆盖的默认值,或者反之使用可选参数来覆盖来自搜索字符串的任何参数。这可以使用 jQuery.extend() 函数与返回的对象一起完成

var searchOptions = $.fn.dataTable.ext.deepLink( [
    'order'
];
var defaultOptions = {
    order: [[ 2, 'desc' ]]
};

$('#myTable').DataTable(
    $.extend( defaultOptions, searchOptions )
);

如何运作?

既然我们知道如何使用它,如果您有兴趣了解它的工作原理,那就继续阅读。它的确非常简单!让我们首先回到我在论坛中的标准回复,即应该使用搜索字符串来设置参数值。如果我们假设整个搜索字符串将用于搜索该表(例如,/table?mySearchTerm),我们可能会使用

$('#myTable').DataTable( {
    search: {
        search: location.search.replace(/^\?/, '')
    }
} );

现在关键是要将搜索字符串分解为键值对。有点令人惊讶的是,浏览器中没有对此的 API,但使用 String.prototype.splitdecodeURIComponent() 便可以轻易实现

$.fn.dataTable.ext.deepLink = function(whitelist) {
    var search = location.search.replace(/^\?/, '').split('&');
    var out = {};

    for (var i = 0, ien = search.length; i < ien; i++) {
        var pair = search[i].split('=');
        var key = decodeURIComponent(pair[0]);
        var value = decodeURIComponent(pair[1]);

        ...
    }

    return out;
};


### Casting values

The query string can only directly hold string values (it is a string itself after all), unless we use a data schema such as JSON. JSON isn't pretty to look at in a URL, so we want to avoid that here. The type always being a string is an issue in this case as certain DataTables parameters expect other types - for example `-init displayStart` must be a `Number` and not a `String` while `-init paging` is a Boolean. As such we need to [cast](https://en.wikipedia.org/wiki/Type_conversion) the string values into their typed counterparts:

```js
if (value === 'true') {
    value = true;
}
else if (value === 'false') {
    value = false;
}
else if (!value.match(/[^\d]/)) {
    value = value * 1;
}
else if (value.indexOf('{') === 0 || value.indexOf('[') === 0) {
    // Try to JSON parse for arrays and obejcts
    try {
        value = $.parseJSON( value );
    }
    catch(e){}
}

缺点是无法将 search.search 设置为 true,因为会因上述代码而转换为布尔值。我觉得出现这种情况的可能性比较小,但如果您遇到了,则上述代码片段需要根据您的需要进行修改。

编写嵌套值

您可能在上面的示例中注意到我们经常使用 search.search,因为这是我认为该脚本最常使用的参数之一。但是,它的 Javascript 对象版本实际上是 { search: { search: ... } } - 即一个嵌套对象。要从字符串表示法转换,我们可以使用 DataTables 内置的一个函数根据一个点分隔的字符串构建嵌套对象:$.fn.dataTable.ext.internal._fnSetObjectDataFn(这是用于 columns.data 的)。这个函数不是一个记录在案的 API,但下一个主要版本会看到它被提升为这样(尽管使用了一个更容易访问的名称),因为它对于插件和附加脚本非常有用!

var setBuilder = $.fn.dataTable.ext.internal._fnSetObjectDataFn;

if (whitelist === 'all' || $.inArray(key, whitelist) !== -1) {
    var setter = setBuilder(key);
    setter(out, value);
}

源代码和 Git

有关该脚本的完整记录源代码,请 在 GitHub 上查找。如果您有任何增强建议,欢迎提出拉取请求!