替换 Laravel 分页组件默认生成的模板
本人博客原文地址: https://www.insp.top/article/php-knowledge... 转载请注明原文地址!
在使用 Laravel 分页功能时,需要配合使用前端框架 Bootstrap
的分页组件,这两者结合甚为紧密。可是由于我的博客更换为 AmazeUI,而 AmazeUI 分页组件使用的 CSS 类选择器是 .am-pagination
而不是 Bootstrap 的 .pagination
。
那么如何在不修改框架代码的前提下替换默认的 Laravel Pagination 生成的 html 模板呢?本文将通过利用 Laravel Service Provider (服务提供者)实现该需求。通过了解本文的内容大家也可以实现更多的分页样式。
关于 Laravel 的 Pagination (分页)组件#
Laravel 的分页组件其实从一开始就考虑到这个需求,但是文档上根本就没有写如何操作,导致很多人误解 Laravel 的分页组件并不适用于复杂场景。其实通过查阅 API 文档或者直接查看 Illuminate\Pagination\Paginator
类,可以发现 laravel 的分页组件是十分灵活的。查看该类的 render
方法,可以注意到实际生成分页 html 模板的是一个实现 Illuminate\Contracts\Pagination\Presenter 接口的实例,我们只需要实现一个基于该接口的类,并传入该方法即可。
实现过程#
创建必要的类#
通过分析,我们首先要创建一个实现 Illuminate\Contracts\Pagination\Presenter 接口的实例。本文中案例中,我们在框架 app 目录下创建了一个类 NewPaginationPresenter, 命名空间是 App,该类实现上面我们讲的接口。
命名空间为什么是 App?因为 laravel 默认的,在 App 目录下的类命名空间一般都是 App(当然通过 artisan 命令修改过则以修改的为准),之后的
子命名空间
都按照 PSR-4 规范对应。
实现必要的方法#
接口要求必须实现 hasPage
和 render
方法,其中 render 方法返回的值就是我们生成的目标 html 模板,因此我们主要就是实现这个方法。
对于 Laravel 默认的分页 html 代码的生成,是由 Illuminate\Pagination\BootstrapThreePresenter 类完成的,该类正是实现了之前我们说的那个接口,由于我们仅需要修改生成的 html 中的 dom 的 class 属性,所以我们没必要完完全全重写,只需要继承 Illuminate\Pagination\BootstrapThreePresenter 类,然后对其中的部分方法稍微改造即可。
实际上我们通过文档也看得出一些端倪,laravel 的分页组件有 paginate 和 simplePaginate 两个方法,实际上这两个方法分别通过 Illuminate\Pagination 命名空间下的 BootstrapThreePresenter 类和 SimpleBootstrapThreePresenter 类生成目标 html,而 SimpleBootstrapThreePresenter 实际上只是继承 BootstrapThreePresenter,仅仅修改了其父类的两个方法而已。
我们创建的类同样可以继承 Illuminate\Pagination\BootstrapThreePresenter 类,我们的目的是让其生成符合 AmazeUI 分页组件的 html 代码格式。
默认 Illuminate\Pagination\BootstrapThreePresenter 有这样几个方法:
class BootstrapThreePresenter implements PresenterContract {
// 此处省略
public function render()
{
if ($this->hasPages())
{
return sprintf(
'<ul class="pagination">%s %s %s</ul>',
$this->getPreviousButton(),
$this->getLinks(),
$this->getNextButton()
);
}
return '';
}
protected function getAvailablePageWrapper($url, $page, $rel = null)
{
$rel = is_null($rel) ? '' : ' rel="'.$rel.'"';
return '<li><a href="'.htmlentities($url).'"'.$rel.'>'.$page.'</a></li>';
}
protected function getDisabledTextWrapper($text)
{
return '<li class="disabled"><span>'.$text.'</span></li>';
}
protected function getActivePageWrapper($text)
{
return '<li class="active"><span>'.$text.'</span></li>';
}
// 此处省略
}
通过发现,我们发现只需要修改上述代码中出现的 getActivePageWrapper、 getDisabledTextWrapper、 render 方法中的关于生成 html 的内容即可,比如 AmazeUI 的分页 html 结构和 Bootsrtap 一致,只是 CSS 选择器由 Bootstrap 的 .pagination 变为 .am-pagination 而已,那么我们就将 render 方法中的 .pagination 改为 .am-pagination 即可。其余的替换方式类似。
当然对于需求更多,则可以对 render 方法整体改造,总而言之,生成的 html 由该方法返回即可,至于生成什么、逻辑是什么样子的则由你来决定。
替换默认的生成类#
我们知道,Pagination 组件的 render 方法实际上是调用 Presenter 接口实现的实例的 render 方法,通过将实例传入 render 即可。但是这样并不科学,首先是我们上面实现的 Presenter 实例的构造函数需要其他参数,同时还需要 Pagination 实例的传入!
这样看来十分麻烦且不实用。
但我们发现 Pagination 类有一个静态方法 presenter
,该方法的作用就是注册默认 Presenter 实例,我们可以在任意位置(当然必须要在使用 Pagination 的 render 方法前)通过该静态方法注册默认 Presenter 实例即可。
为了方便全局使用,我们可以通过使用 Service Provider 在框架启动之初就注册该实例。
通过 artisan 创建一个 Service Provider,在 boot 方法中这样写:
<?php namespace App\Providers;
use App\NewPaginationPresenter;
use Illuminate\Pagination\Paginator;
use Illuminate\Pagination\AbstractPaginator;
use Illuminate\Support\ServiceProvider;
class PaginationProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
// 使用自定义分页模板
Paginator::presenter(function (AbstractPaginator $paginator) {
return new NewPaginationPresenter($paginator);
});
}
/**
* Register the application services.
*
* @return void
*/
public function register()
{
//
}
}
保存后,将该 Service Provider 加入 config 目录下的 app.php 配置文件的 providers 项里。好了,大功告成!!!
推荐文章: