【问题标题】:Server Side (PHP) filtering and ordering with Ajax and infinite scroll使用 Ajax 和无限滚动的服务器端 (PHP) 过滤和排序
【发布时间】:2013-10-31 05:38:51
【问题描述】:

我已经在我的项目 (https://github.com/webcreate/infinite-ajax-scroll) 中实现了infinite-ajax-scroll 插件。它是一个显示一长串 div 的 PHP 项目。无限滚动使用服务器端分页。我也有服务器端过滤和排序,理想情况下希望它使用 Ajax,以便它与我的无限滚动很好地工作。如何使用 Ajax 传递过滤器?我找到了有关如何使用 JQuery 进行过滤的教程,但都没有使用 PHP。

我确实找到了http://isotope.metafizzy.co/,它同时具有过滤和无限滚动功能,但在文档中它建议不要同时使用这两种功能,这对我来说是一个巨大的耻辱,因为它看起来像一个很棒的插件。

任何人都可以就我的最佳方法提出建议吗?如果我需要在选择新过滤器时重置无限滚动,那很好。但是我将如何做到这一点以及如何将选定的过滤器传递给无限滚动?

以下是我目前所拥有的。

    $cat = (isset($_GET['cat']) ? urldecode($_GET['cat']) : ''); 
    $page = (int) (!isset($_GET['p'])) ? 1 : $_GET['p'];
    $start = ($page * $pagelimit) - $pagelimit;
    $limit = $pagelimit*$page; 

    //get total number of discounts for search
    $total_items = Stuff::countItems($cat);

    if( $total_items > ($page * $limit) ){
      $next = ++$page;
    }

    //get items
$items = Stuff::getItems($cat, $sortby, $dir, $start, $limit);

if(!$items){
  header('HTTP/1.0 404 Not Found');
  echo 'Page not found!';
  exit();
} 

?>
<html>
    <head>
        <title></title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
        <script type="text/javascript" src="js/jquery-ias.min.js"></script>
        <script type="text/javascript">
          $(document).ready(function() {
            // Infinite Ajax Scroll configuration
            jQuery.ias({
              container : '.wrap', // main container where data goes to append
              item: '.item', // single items
              pagination: '.paginate', // page navigation
              next: '.paginate a', // next page selector
              loader: '<img src="css/ajax-loader.gif"/>', // loading gif
              noneleft: 'No more items', //Contains the message to be displayed when there are no more pages left to load
              triggerPageThreshold: 5, // show "load more" if scroll more than this to stop
              trigger: "Load more items"
            });
          });
        </script>
    </head>
    <body>
    <div class="wrap">    
        <?php
        echo 'TOTAL: '.$total_items .'<br />';

        //filter through categories*/
        echo 'FILTER BY CATEGORY:';
        foreach ($categories as $category){
            $categoryURL = urlencode($category);
            echo "<a href=\"index.php?cat=$categoryURL\">$category<a/> | ";
        }       
        //loop through and display items
       foreach ($items as $id => $item){

           echo "<div style=\"border:1px solid green;margin-bottom:5px;\" class=\"item\" id=\"item-$id\">
                    ID: $id <br />
                    $item[name]<br />                                                                                                                                                                                                                                
                    $item[cat]<br />
                    $item[description]<br />
            </div>";
        }
        ?>
    <!--paginagation-->
    <?php if (isset($next)): ?>
    <div class="paginate">
      <a href='index.php?cat=<?php echo $cat?>&p=<?php echo $next?>'>Next</a>
    </div>
    <?php endif?>
    </div>
    </body>
</html>

【问题讨论】:

  • 所以您想使用 html/javascript 指定一个过滤器并通过 AJAX 将其提交到您的服务器端脚本,我说对了吗?如果是这样,什么样的过滤器?
  • 我也在试图找出其中的哪一部分不适合你。类别应该被过滤——应该是什么没有发生?
  • 是的,该类别正在过滤,但仅在重新加载页面后。应用过滤器时,我正在尝试使用 ajax 加载新结果。然后我可能需要重置无限滚动。然后我需要传递选定的过滤器(类别),以便无限滚动与选定的过滤器一起工作。希望澄清一下。

标签: php ajax filtering jquery-isotope infinite-scroll


【解决方案1】:

只有在客户端(对于已加载的数据)和服务器(对于要加载的未来页面)都应用过滤器时,无限滚动和过滤才有意义。

但是在应用了一些完全不同的过滤器或排序之后,我认为用户希望被带回第一页(或滚动回顶部以进行无限滚动)。 丢失一些已经加载的结果是唯一的方法。你也许可以cache 这些结果来提高速度。

为了简单起见,我建议您开始使用KnockoutJS 或一些类似的客户端 MVC 库。 jQuery 非常适合复杂性。在某些时候,您会发现自己需要更好的东西。

Here's a cleaned up extract 我前一段时间开发的一个应用程序需要类似的东西。 (edit link)

您根本不需要那个“页面”参数。我使用它是为了让我的“假”提供者可以返回顺序的、可读的名称。

对于当前查询,您需要随时知道服务器端(可能是$_SESSION),您向客户端发送了多少结果。

类似这样的:

function getResults($query) {
    if($_SESSION['query']['category'] !== $query['category']) {
        if(!array_key_exists($query['category'], $_SESSION['resultsSent'])) {
            $_SESSION['resultsSent'][$query['category']] = 0;
        }
        $_SESSION['query'] = $query; 
    }

    $sql = 'SELECT * FROM foo WHERE category = ? LIMIT ?, ?';
    $data = $db->select($sql, array($_SESSION['query']['category'],  $_SESSION['resultsSent'][$query['category']], 10);

     $_SESSION['resultsSent'][$query['category']] += count($data);

    return json_encode($data);
}

if(!array_key_exists('query', $_SESSION)) {
    $_SESSION['resultsSent'] = array();
    $_SESSION['query'] = array(); // maybe some defaults here?
}

if(array_key_exists('query', $_POST)) {
    echo getResults($_POST['query']);
}

您必须编写一个执行 AJAX 调用的resultsService。 大概是这样的:

function resultsService() {
    this.query = function(query, success) {
        jQuery.post({
            url: 'index.php', 
            data: query,
            success: success
        });
    }
}

在那之后,你所要做的就是把你的无限滚动库放在上面。

这取决于以下事实:(1) 在客户端上,您永远不会删除已加载的数据,如果它不适合当前过滤器,您只需将其隐藏;(2) 对于每个可能的过滤器组合,您的服务器都知道它有多少数据发送,以便它不会再次将其发送回去。

如果您有更复杂的过滤器,但结果不是排他性的(多个过滤器组合可能会返回一个结果 - 想想 priceratingnumber of房间,而不是类别),那么您最终会向客户端发送重复的内容。除了重置整个列表之外,没有真正的解决方案。您可以尝试跟踪您发送给客户端的所有单个结果,不仅是计数,并在查询时将它们过滤掉 (WHERE id NOT IN (1, 2, 17, 20, ...)),但这绝对不适用于大量数据。

对于排序,除了确切知道您发送给客户的内容,或者显然是重置列表之外,绝对没有其他解决方案。

POSTing 一个 JS 对象作为 JSON 编码字符串 (ko.toJS(this.query)),然后在 PHP 中 json_decodeing 它。 无论您如何构建该 JS 对象,将其发送为 JSON 都比自己手动将其序列化为 GET 参数要好。

此外,最好对所有过滤器类型使用通用格式并通过设置模式服务器端处理它们。

对于['category': 1, 'subcategory':2, 'user': 1234],我将定义categoryFiltersubcategoryFilteruserFilter,使用call_user_func 调用它们,并将过滤后的值作为参数传递给您的查询,为每个值添加位。

$query = DB::table('stuff');

$filters = json_decode($_POST['query']);
foreach($filters as $filterName => $value) {
    $query = call_user_func_array($filterName . 'Filter', array($query, $value));
}

$results = $query->get();

function categoryFilter($query, $value) {
    $query->where('category_id', '=', $value);

    return $query;
}

实际代码的外观以及构建 SQL 查询的难易程度取决于您使用的内容。我上面使用的 DB 类是与 Laravel 捆绑在一起的。

即使使用基本的 jQuery,在客户端构建查询对象也不应该那么难。

【讨论】:

  • 感谢您的深入回复。我在这方面做了很多工作,不想开始改变一切以开始使用 Knockout,但感谢您的建议,我会在未来研究这个问题。我很乐意在选择新过滤器时重置列表。我对 Ajax 不是很好,所以只是在寻找有关如何使用 ajax 应用过滤器并将这些过滤器传递给无限滚动的建议
  • 有关在服务器端应用过滤器的想法,请参阅上面我编辑的答案。
  • 谢谢您,但是如何将选定的过滤器传递给无限滚动?
  • 这两个无限滚动库都希望将“下一页”URL 的选择器作为配置参数。因此,您将无法POST 对其进行任何操作。 JSON 序列化过滤器并将它们作为GET 参数发送,或者深入研究这些库的文档并了解如何提供自己的“加载”功能。 Paul Irish 的版本 (github.com/paulirish/infinite-scroll) 接受自定义的“加载”回调函数参数,并且应该很容易实现。
【解决方案2】:

这样想:当您进行过滤时,您会更改整个结果,因此您需要重新加载数据并重置滚动。这就是为什么你不应该同时使用过滤和无限滚动。

我在之前的项目中做了同样的事情。希望它对你有用。

【讨论】:

  • 是的,我很乐意重置卷轴。我想我会期待的。您在之前的项目中是如何做到的?你能建议使用什么来重置滚动条的 Ajax 过滤吗?
  • 我使用了Facescroll。默认情况下它不支持无限滚动,但滚动条可以动态添加到一段内容中,因此我们自定义库以处理无限滚动。
    我们的过滤是即时搜索。当用户输入一个字符时,我们 setTimeout 来调用一个 ajax 函数。 $('#searchInput').keydown(function(event) { if (windowDrawing.searchTimer) { clearTimeout(windowDrawing.searchTimer); } windowDrawing.searchTimer = setTimeout(function() { myWindowProcess.ajaxGetWindows(); }, 200); });
猜你喜欢
  • 2013-12-01
  • 2020-11-28
  • 1970-01-01
  • 1970-01-01
  • 2012-02-27
  • 2013-06-28
  • 2016-06-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多