如何在页面加载时从表中加载一定数量的行,并且仅在用户加载它们时才加载更多行?

Posted

技术标签:

【中文标题】如何在页面加载时从表中加载一定数量的行,并且仅在用户加载它们时才加载更多行?【英文标题】:How can i load a set number of rows from a table on pageload and only load further rows when the user loads them? 【发布时间】:2020-07-03 04:57:16 【问题描述】:

我有一个使用 DataTables 的表格,它包含大量行,因此这会导致页面加载非常缓慢,因为我假设浏览器会等到表格填满后再显示页面。

我只想加载表格的一页(10 行),并且只在用户浏览表格时显示更多数据,显示加载标志也很好。

我研究并听说了一个名为“deferRender”的 DataTables 函数,它应该可以满足我的需求,但我无法让它与我的表一起使用。

我的表格有 8 列 + html 是使用 php 生成的,它从文本文件中的数据构建表格:

<?php


     $tdcount = 1; $numtd = 8; // number of cells per row
     $str = "<table id=\"table1\" class=\"table1 table table-striped table-bordered\">
                                     <thead>
                                     <th>1</th>
                                     <th>2</th>
                                     <th>3</th>
                                     <th>4</th>
                                     <th>5</th>
                                     <th>6</th>
                                     <th>7</th>
                                     <th>8</th>
                 </thead>
                                     <tbody>

 ";
     $f = fopen("tabledata.txt", "r");
     if ( $f === FALSE ) 
 exit;
    
     while (!feof($f)) 
         $arrM = explode(",",fgets($f));
         $row = current ( $arrM );
         if ($tdcount == 1)
             $str .= "<tr>"; $str .= "<td>$row </td>";
         if ($tdcount == $numtd) 
             $str .= "</tr>";
             $tdcount = 1;
          else 
             $tdcount++;
         
     
     if ($tdcount!= 1) 
         while ($tdcount <= $numtd) 
             $str .= "<td>&nbsp;</td>"; $tdcount++;
          $str .= "</tr>";
     
     $str .= "</tbody></table>";
     echo $str;

然后我用下面的代码把它变成一个数据表:

<script>
        $(document).ready(function() 
        $('#table1').basictable(
          forceResponsive: false
          );
        $('#table1').DataTable(  "order": [[ 0, "desc" ]]  );

          );

</script>

我已阅读此处的说明:https://datatables.net/examples/server_side/defer_loading.html 并且知道我需要向 JS 添加参数:

"processing": true,
"serverSide": true,
"ajax": "scripts/server_processing.php",
"deferLoading": 57

并使用 server_processing 脚本,但是该示例仅显示如何在连接到数据库时使用它,而不是在使用 php 从文本文件加载数据时使用它。

我怎样才能做到这一点?

【问题讨论】:

您的数据是存储在数据库中还是存储在文件中有些偶然 - 您需要实现以支持 DataTables 的核心服务器端处理大致相同。查看从 DataTables 自动传递到您的服务器的数据结构(在 Sent Parameters 部分中描述)。并查看您需要填充并传递回 DataTables 作为响应的数据结构(在Returned Data 部分中描述)。 只是补充一点:“延迟加载”是一种额外的方式来优化您的服务器端处理 - 但它不是服务器端处理工作方式的核心。如果我的笔记没有帮助,我可以提供更长的答案 - 但请查看上面的链接,以及最简单的服务器端案例的数据结构。这应该有助于为您指明正确的方向。如果我没有抓住重点,当然可以告诉我! 谢谢,这确实有点帮助,但是如果你能为我的问题提供一个很好的详细解决方案,我仍然对如何做到这一点感到困惑@andrewjames 【参考方案1】:

这将纯粹关注“服务器端”解决方案的 DataTables 方面。如何编写支持它所需的服务器端逻辑超出了此答案的范围。但我希望这些笔记至少能阐明这种逻辑需要是什么,以及如何处理它。

假设

假设您有一个文本文件,其中包含 1,000 行这样的数据(或一百万行 - 但太多行无法同时发送到浏览器和 DataTables)。文本文件是一个简单的管道分隔文件,包含三个字段:

id|name|description
1|widget_1|This is a description for widget 1
2|widget_2|This is a description for widget 2
3|widget_3|This is a description for widget 3
...
1000|widget_1000|This is a description for widget 1000

您希望使用服务器端处理一次将 10 个项目发送到 DataTables。

您的数据映射到一个简单的 JSON 结构,如下所示 - 一个对象数组(每个对象是一个记录):

[
    
        "id": 1,
        "name": "widget_1",
        "description": "This is a description for widget 1"
    ,
    
        "id": 2,
        "name": "widget_2",
        "description": "This is a description for widget 2"
    ,
    ... // more records...
]

数据表定义

您的数据表定义看起来像这样 - 在这个阶段故意非常简单:

<body>

<div style="margin: 20px;">

<table id="demo" class="display dataTable cell-border" style="width:100%">
</table>

</div>

<script type="text/javascript">

  $(document).ready(function() 
    $('#demo').DataTable(
      serverSide: true,
      ajax: 
        url: 'http://localhost:7000/data',
        type: 'POST'
      ,
      columns: [
         title: 'ID',
          data: 'id' ,
         title: 'Name',
          data: 'name' ,
         title: 'Description',
          data: 'description' 
      ]
    );

  );
</script>

</body>

初始响应

当网页首次显示时,它会向 URL (http://localhost:7000/data) 发送一个初始 POST 请求,并期望从 Web 服务器接收 JSON 响应,其中包含要显示的数据。

由于 DataTables 使用的是serverSide: true,DataTables 将期望 JSON 具有特定的结构,如 here 所述。

具体来说,服务器必须将所有必填字段(drawrecordsTotalrecordsFiltereddata)添加到它发送到 DataTables 的 JSON 中。

在我们的例子中,它看起来像这样 - 请注意,它只是我们之前提到的 JSON 结构,添加了一些额外的元数据字段:


    "draw": 1,
    "recordsTotal": 1000,
    "recordsFiltered": 1000,
    "data": [
        "id": 1,
        "name": "widget_1",
        "description": "This is a description for widget 1"
    , 
        "id": 2,
        "name": "widget_2",
        "description": "This is a description for widget 2"
    , 
        "id": 3,
        "name": "widget_3",
        "description": "This is a description for widget 3"
    , 
        "id": 4,
        "name": "widget_4",
        "description": "This is a description for widget 4"
    , 
        "id": 5,
        "name": "widget_5",
        "description": "This is a description for widget 5"
    , 
        "id": 6,
        "name": "widget_6",
        "description": "This is a description for widget 6"
    , 
        "id": 7,
        "name": "widget_7",
        "description": "This is a description for widget 7"
    , 
        "id": 8,
        "name": "widget_8",
        "description": "This is a description for widget 8"
    , 
        "id": 9,
        "name": "widget_9",
        "description": "This is a description for widget 9"
    , 
        "id": 10,
        "name": "widget_10",
        "description": "This is a description for widget 10"
    ]

构建这个 JSON 是服务器的责任——服务器数据集的前 10 条记录。服务器还告诉 DataTables 它总共有 1,000 条记录,并且它还没有过滤掉任何数据 - 因此过滤后总共有 1,000 条记录。

DataTables 需要所有这些信息,因此它知道要显示多少个分页按钮,以及要显示哪些分页数据。

请注意,完成所有这些工作完全是服务器的责任——这就是为什么它被称为“服务器端”处理。

客户端(浏览器)只有 10 条记录要呈现 - 所以这很快就会发生。

(我刚刚注意到屏幕截图提到了“500 条记录”——这是我的服务器端代码中的一个错误——没有过滤器,所以我需要修复它)。

后续请求

当用户单击页面导航按钮(例如页面“4”)时,会触发从 DataTables 到服务器的新请求。 DataTables 使用here 描述的字段自动构建此请求。

请求作为表单数据发送。

在我们的示例中,请求如下所示:

"Form data": 
    "draw": "5",
    "columns[0][data]": "id",
    "columns[0][name]": "",
    "columns[0][searchable]": "true",
    "columns[0][orderable]": "true",
    "columns[0][search][value]": "",
    "columns[0][search][regex]": "false",
    "columns[1][data]": "name",
    "columns[1][name]": "",
    "columns[1][searchable]": "true",
    "columns[1][orderable]": "true",
    "columns[1][search][value]": "",
    "columns[1][search][regex]": "false",
    "columns[2][data]": "description",
    "columns[2][name]": "",
    "columns[2][searchable]": "true",
    "columns[2][orderable]": "true",
    "columns[2][search][value]": "",
    "columns[2][search][regex]": "false",
    "order[0][column]": "1",
    "order[0][dir]": "asc",
    "start": "30",
    "length": "10",
    "search[value]": "",
    "search[regex]": "false"

这些字段告诉服务器它需要知道的一切,因此它可以准备正确的响应。

在我们的例子中,最重要的字段是:

"start": "30",
"length": "10"

从第 30 行开始,提供 10 条记录。

同样,服务器有责任准备一个准确反映所请求数据的 JSON 响应。

在我们的例子中,这意味着服务器需要有逻辑来读取文本文件到正确的起点(数据行 31 - 记住偏移量从零开始),总共 10 行(第 31 到 40 行)。

上述来自 DataTables 的请求中的其他字段描述了如何对数据进行排序和过滤。在我们的例子中,没有过滤器"search[value]": "", - 数据将按第一列升序排序。

最后说明

我故意不描述以下内容:

1) 您的服务器端代码如何处理它发送回 DataTables 的 JSON 响应的创建;

2) 您的服务器端代码如何解析从 DataTables 接收的表单请求。

这完全取决于您的服务器端技术是什么。数据表不在乎。它只是传递 JSON 消息 - 它与服务器端实现分离 - 应该如此。

关于here 中描述的“延迟渲染”选项,如果您觉得需要,可以选择添加它。但我建议先让一个更基本的服务器端实现工作。

【讨论】:

以上是关于如何在页面加载时从表中加载一定数量的行,并且仅在用户加载它们时才加载更多行?的主要内容,如果未能解决你的问题,请参考以下文章

在Vue中加载页面时从列表中调用json

如何在 WebView 中仅加载 .html 页面并在 iOS 的 Safari 中加载所有 www 页面?

在鼠标输入时从数组中加载下一个图像

如何在运行时从文件中加载 HTML 模板?

liquibase 从表中加载数据

ORM(Linq-SQL EF)是不是从表中加载整个数据集?