PHP框架Laravel插件Pagination实现自定义分页

前端技术 2023/09/09 PHP

Laravel 的分页很方便,其实扩展起来也挺容易的,下面就来做个示例,扩展一下 paginate() 和 simplePaginate() 方法,来实现我们自定义分页样式,比如显示 \"上一页\" 和 \"下一页\" ,而不是 \"《\" 和 \"》\" ,当然扩展的方法掌握了你就可以肆无忌惮的扩展一个你想要的分页了,比如跳转到某一页,分页显示一共多少记录,当前显示的记录范围等等巴拉巴拉的。。。

5.1和5.2应该是同样的方法,我这里用的是5.2的版本。文档告诉我们 Paginator 对应于查询语句构造器和 Eloquent 的  simplePaginate 方法,而  LengthAwarePaginator 则等同于  paginate 方法。那我们还是来看下源码,具体这个  paginate 是如何实现 render() 的,

Illuminate/Pagination/LengthAwarePaginator.php

<?php

namespace Illuminate\\Pagination;

......

class LengthAwarePaginator extends AbstractPaginator implements Arrayable, ArrayAccess, Countable, IteratorAggregate, JsonSerializable, Jsonable, LengthAwarePaginatorContract 
{
......
  public function render(Presenter $presenter = null)
  {
    if (is_null($presenter) && static::$presenterResolver) {
      $presenter = call_user_func(static::$presenterResolver, $this);
    }

    $presenter = $presenter ?: new BootstrapThreePresenter($this);

    return $presenter->render();
  }
......
}

render() 中传入的是一个 Presenter 的实例,并调用这个实例化的 render 方法来实现分页的显示的。如果没有则调用 BootstrapThreePresenter 中 render() 的,来看看 BootstrapThreePresenter 是干嘛的

Illuminate/Pagination/BootstrapThreePresenter.php

<?php

namespace Illuminate\\Pagination;

use Illuminate\\Support\\HtmlString; 
use Illuminate\\Contracts\\Pagination\\Paginator as PaginatorContract; 
use Illuminate\\Contracts\\Pagination\\Presenter as PresenterContract;

class BootstrapThreePresenter implements PresenterContract 
{
  use BootstrapThreeNextPreviousButtonRendererTrait, UrlWindowPresenterTrait;

  /**
   * The paginator implementation.
   *
   * @var \\Illuminate\\Contracts\\Pagination\\Paginator
   */
  protected $paginator;

  /**
   * The URL window data structure.
   *
   * @var array
   */
  protected $window;

  /**
   * Create a new Bootstrap presenter instance.
   *
   * @param \\Illuminate\\Contracts\\Pagination\\Paginator $paginator
   * @param \\Illuminate\\Pagination\\UrlWindow|null $window
   * @return void
   */
  public function __construct(PaginatorContract $paginator, UrlWindow $window = null)
  {
    $this->paginator = $paginator;
    $this->window = is_null($window) ? UrlWindow::make($paginator) : $window->get();
  }

  /**
   * Determine if the underlying paginator being presented has pages to show.
   *
   * @return bool
   */
  public function hasPages()
  {
    return $this->paginator->hasPages();
  }

  /**
   * Convert the URL window into Bootstrap HTML.
   *
   * @return \\Illuminate\\Support\\HtmlString
   */
  public function render()
  {
    if ($this->hasPages()) {
      return new HtmlString(sprintf(
        \'<ul class=\"pagination\">%s %s %s</ul>\',
        $this->getPreviousButton(),
        $this->getLinks(),
        $this->getNextButton()
      ));
    }

    return \'\';
  }
......
}

这里可以看到 BootstrapThreePresenter 实现了 PresenterContract 的接口, render() 才是分页显示的真正实现,构造方法中的第一个参数 PaginatorContract 其实就是一个 Paginator 我们继续看下 PresenterContract 也就是 Presenter 接口中定义了什么方法需要实现

illuminate/contracts/Pagination/Presenter.php

<?php

namespace Illuminate\\Contracts\\Pagination;

interface Presenter 
{
  /**
   * Render the given paginator.
   *
   * @return \\Illuminate\\Contracts\\Support\\Htmlable|string
   */
  public function render();

  /**
   * Determine if the underlying paginator being presented has pages to show.
   *
   * @return bool
   */
  public function hasPages();
}

其中定义了 render 和 hasPages 方法需要实现

好了,那我们现在已经很清晰了,我们要自定义分页的显示,那么就要写一个我们自己的 Presenter 来实现接口中的 render() 和 hasPages() 就可以了。

首先就来简单的实现一个paginate(),显示出来\"上一页\"和\"下一页\",中间是分页数字的例子。

新建文件如下(个人习惯)

app/Foundations/Pagination/CustomerPresenter.php

<?php 
namespace App\\Foundations\\Pagination;

use Illuminate\\Contracts\\Pagination\\Presenter as PresenterContract; 
use Illuminate\\Contracts\\Pagination\\LengthAwarePaginator as PaginatorContract; 
use Illuminate\\Pagination\\UrlWindow; 
use Illuminate\\Support\\HtmlString; 
use Illuminate\\Pagination\\BootstrapThreeNextPreviousButtonRendererTrait; 
use Illuminate\\Pagination\\UrlWindowPresenterTrait;

class CustomerPresenter implements PresenterContract 
{
  use BootstrapThreeNextPreviousButtonRendererTrait, UrlWindowPresenterTrait;

  protected $paginator;

  protected $window;

  /**
   * Create a new Bootstrap presenter instance.
   *
   * @param \\Illuminate\\Contracts\\Pagination\\Paginator $paginator
   * @param \\Illuminate\\Pagination\\UrlWindow|null $window
   * @return void
   */
  public function __construct(PaginatorContract $paginator, UrlWindow $window = null)
  {
    $this->paginator = $paginator;
    $this->window = is_null($window) ? UrlWindow::make($paginator) : $window->get();
  }

  /**
   * Determine if the underlying paginator being presented has pages to show.
   *
   * @return bool
   */
  public function hasPages()
  {
    return $this->paginator->hasPages();
  }

  /**
   * Convert the URL window into Bootstrap HTML.
   *
   * @return \\Illuminate\\Support\\HtmlString
   */
  public function render()
  {
    if ($this->hasPages()) {
      return new HtmlString(sprintf(
        \'<ul class=\"pagination\">%s %s %s</ul>\',
        $this->getPreviousButton(\'上一页\'),//具体实现可以查看该方法
        $this->getLinks(),
        $this->getNextButton(\'下一页\')//具体实现可以查看该方法
      ));
    }

    return \'\';
  }

  /**
   * Get HTML wrapper for an available page link.
   *
   * @param string $url
   * @param int $page
   * @param string|null $rel
   * @return string
   */
  protected function getAvailablePageWrapper($url, $page, $rel = null)
  {
    $rel = is_null($rel) ? \'\' : \' rel=\"\' . $rel . \'\"\';

    return \'<li><a href=\"\' . htmlentities($url) . \'\"\' . $rel . \'>\' . $page . \'</a></li>\';
  }

  /**
   * Get HTML wrapper for disabled text.
   *
   * @param string $text
   * @return string
   */
  protected function getDisabledTextWrapper($text)
  {
    return \'<li class=\"disabled hide\"><span>\' . $text . \'</span></li>\';
  }

  /**
   * Get HTML wrapper for active text.
   *
   * @param string $text
   * @return string
   */
  protected function getActivePageWrapper($text)
  {
    return \'<li class=\"active\"><span>\' . $text . \'</span></li>\';
  }

  /**
   * Get a pagination \"dot\" element.
   *
   * @return string
   */
  protected function getDots()
  {
    return $this->getDisabledTextWrapper(\'...\');
  }

  /**
   * Get the current page from the paginator.
   *
   * @return int
   */
  protected function currentPage()
  {
    return $this->paginator->currentPage();
  }

  /**
   * Get the last page from the paginator.
   *
   * @return int
   */
  protected function lastPage()
  {
    return $this->paginator->lastPage();
  }

}

就这么简单,主要就是 render() 方法,如果项目中需要修改分页样式,或者添加分页跳转之类的需求只要重写其中的各项显示的方法中的html元素就可以了,很灵活,在blade模板中也需要修该,比如我们的 Paginator 叫 $users ,默认的分页显示是这样的:

{!! $users->render() !!}
修改成我们自定义后的分页显示:

{!! with(new \\App\\Foundations\\Pagination\\CustomerPresenter($categories))->render() !!}
好了,这样在页面应该就可以看到分页链接中含有 \"上一页\"和\"下一页\"加数字的样式了。

那么如果扩展simplePaginate?其实很简单,只要继承刚才的 CustomerPresenter ,实现 hasPages 和 render ,至于为什么可以按照我上面查看源码的方式看一下就知道了,比如我们改成\"上一篇\"和\"下一篇\"

新建App\\Foundations\\Pagination\\CustomerSimplePresenter.php

<?php 
namespace App\\Foundations\\Pagination;


use Illuminate\\Support\\HtmlString; 
use Illuminate\\Contracts\\Pagination\\Paginator as PaginatorContract;

class CustomerSimplePresenter extends CustomerPresenter 
{
  /**
   * Create a simple Bootstrap 3 presenter.
   *
   * @param \\Illuminate\\Contracts\\Pagination\\Paginator $paginator
   * @return void
   */
  public function __construct(PaginatorContract $paginator)
  {
    $this->paginator = $paginator;
  }

  /**
   * Determine if the underlying paginator being presented has pages to show.
   *
   * @return bool
   */
  public function hasPages()
  {
    return $this->paginator->hasPages() && count($this->paginator->items()) > 0;
  }

  /**
   * Convert the URL window into Bootstrap HTML.
   *
   * @return \\Illuminate\\Support\\HtmlString
   */
  public function render()
  {
    if ($this->hasPages()) {
      return new HtmlString(sprintf(
        \'<ul class=\"pager\">%s %s</ul>\',
        $this->getPreviousButton(\'上一篇\'),
        $this->getNextButton(\'下一篇\')
      ));
    }

    return \'\';
  }

}

分页显示:

{!! with(new \\App\\Foundations\\Pagination\\CustomerSimplePresenter($categories))->render() !!}

方法就是这个方法,具体修改按照自己需求重写其中对应的显示html元素的方法就可以了。

转载请注明:转载自 Ryan是菜鸟 | LNMP技术栈笔记

以上就是本文的全部内容,希望对大家学习PHP程序设计有所帮助。

本文地址:https://www.stayed.cn/item/23789

转载请注明出处。

本站部分内容来源于网络,如侵犯到您的权益,请 联系我

我的博客

人生若只如初见,何事秋风悲画扇。