Laravel 分页是很方便的一件事情,相对于其他PHP框架来说非常容易。但默认的分页样式往往不能满足我们日常的项目,通过谷歌搜索出来的搜索到的一些知识和结合自己的理解来展示一下Laravel自定义分页的实现
在使用 Laravel 分页功能时,需要配合使用前端框架 Bootstrap
的分页组件,这两者结合甚为紧密。可是由于我的博客分页样式是自定义的,所以 CSS 类选择器并非 Bootstrap
的 .pagination
。
那么如何在不修改框架代码的前提下替换默认的 Laravel Pagination 生成的 html 模板呢?本文将通过利用 Laravel Service Provider(服务提供者)实现该需求。通过了解本文的内容大家也可以实现更多的分页样式。
本人学习Laravel框架的时候都已经是Laravel5了,关于Laravel4的自定义分页就爱莫能助了….
Laravel的分页组件其实一直都考虑到复杂的分页样式,官方文档上并没有说明而已,导致很多人误解Laravel的分页组件并不适用于复杂的场景。其实通过查阅API文档或直接查看 Illuminate\Pagination\Paginator
类,就很容发现Laravel的分页组件是很灵活的。
<?php
namespace Illuminate\Pagination;
...
class LengthAwarePaginator extends AbstractPaginator implements Arrayable, ArrayAccess, Countable, IteratorAggregate, JsonSerializable, Jsonable, LengthAwarePaginatorContract
{
......
/**
* Render the paginator using the given presenter.
*
* @param \Illuminate\Contracts\Pagination\Presenter|null $presenter
* @return string
*/
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();
}
......
}
可以注意到实际生成分页 html 模板的是一个实现 Illuminate\Contracts\Pagination\Presenter
接口的实例,我们只需要实现一个基于该接口的类,并传入该方法即可。为了实现方便,我选择直接继承 Illuminate\Pagination\BootstrapThreePresenter
这个分页类,重写其中我需要修改的样式即可。
通过上面分析,我们只需要创建一个继承 Illuminate\Pagination\BootstrapThreePresenter
的类。在本案例中,我在 repository
中创建一个 PaginationRepository
的自定义分页仓库(本文把自定义分页类放在仓库中,大家也可以放在其他地方),然后重写其中的方法。
<?php
namespace App\Repositories\front;
use Illuminate\Pagination\BootstrapThreePresenter;
/**
* 自定义分页
*/
class PaginationRepository extends BootstrapThreePresenter
{
public function render()
{
if ($this->hasPages())
{
return sprintf(
'<div class="paginations-v2 text-center"><ul class="paginations-v2-list">%s %s %s</ul></div>',
$this->getPreviousButton('Prev'),
$this->getLinks(),
$this->getNextButton('Next')
);
}
return '';
}
/**
* 自定义上一页和下一页按钮禁用样式
* @author 晚黎
* @date 2016-05-10T11:06:31+0800
* @param [type] $text [description]
* @return [type] [description]
*/
protected function getDisabledTextWrapper($text,$bool = true)
{
if ($bool) {
return '<li class="disabled"><span>'.$text.'</span></li>';
}
$className = $text == 'Prev' ? 'previous':'next';
return '<li class="'.$className.' disabled"><span aria-label="'.$className.'"><span aria-hidden="true">'.$text.'</span></span></li>';
}
/**
* 自定义上一页和下一页按钮样式
* @author 晚黎
* @date 2016-05-10T11:22:34+0800
* @param [type] $url [description]
* @param [type] $page [description]
* @param [type] $rel [description]
* @param boolean $bool [description]
* @return [type] [description]
*/
protected function getAvailablePageWrapper($url, $page, $rel = null)
{
$str = $rel == 'prev' ? 'previous':'next';
if ($rel) {
return '<li class="'.$str.'"><a href="'.htmlentities($url).'" aria-label="Next"><span aria-hidden="true">'.$page.'</span></a></li>';
}
$rel = is_null($rel) ? '' : ' rel="'.$rel.'"';
return '<li><a href="'.htmlentities($url).'"'.$rel.'>'.$page.'</a></li>';
}
/**
* 重写 BootstrapThreeNextPreviousButtonRendererTrait 上一页按钮
* @author 晚黎
* @date 2016-05-10T11:07:41+0800
* @param string $text [description]
* @return [type] [description]
*/
public function getPreviousButton($text = '«')
{
// If the current page is less than or equal to one, it means we can't go any
// further back in the pages, so we will render a disabled previous button
// when that is the case. Otherwise, we will give it an active "status".
if ($this->paginator->currentPage() <= 1) {
return $this->getDisabledTextWrapper($text,false);
}
$url = $this->paginator->url(
$this->paginator->currentPage() - 1
);
return $this->getPageLinkWrapper($url, $text, 'prev');
}
public function getNextButton($text = '»')
{
// If the current page is greater than or equal to the last page, it means we
// can't go any further into the pages, as we're already on this last page
// that is available, so we will make it the "next" link style disabled.
if (! $this->paginator->hasMorePages()) {
return $this->getDisabledTextWrapper($text,false);
}
$url = $this->paginator->url($this->paginator->currentPage() + 1);
return $this->getPageLinkWrapper($url, $text, 'next');
}
/**
* 重写 UrlWindowPresenterTrait 中 getPageLinkWrapper 方法,让上一页下一页样式不一样
* @author 晚黎
* @date 2016-05-10T11:18:49+0800
* @param [type] $url [description]
* @param [type] $page [description]
* @param [type] $rel [description]
* @return [type] [description]
*/
protected function getPageLinkWrapper($url, $page, $rel = null)
{
if ($page == $this->paginator->currentPage()) {
return $this->getActivePageWrapper($page);
}
return $this->getAvailablePageWrapper($url, $page, $rel);
}
}
上面代码是我重写上一页、下一页、和中间数字按钮的样式。其中代码可能有优化的地方,大家可以按照自己的编程思想进行修改。当然对于需求更多,则可以对 render()
方法整体改造,总而言之,生成的 html 由该方法返回即可,至于生成什么、逻辑是什么样子的则由你来决定。
Pagination
类有一个静态方法 presenter
,该方法的作用就是注册默认 Presenter
实例,我们可以在任意位置(当然必须要在使用 Pagination
的 render 方法前)通过该静态方法注册默认 Presenter
实例即可。
为了方便全局使用,我们可以通过使用 Service Provider
在框架启动之初就注册该实例。
下面我在自己的一个Server Provider
,在 boot
方法中这样写:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use FrontRepository;
use Illuminate\Pagination\Paginator;
use Illuminate\Pagination\AbstractPaginator;
use App\Repositories\front\PaginationRepository;
class FrontServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
view()->composer('*', function ($view) {
//共享分类数据
$categories = FrontRepository::getCategories();
$view->with('categories',$categories);
});
// 使用自定义分页模板,便于全局使用
Paginator::presenter(function (AbstractPaginator $paginator) {
return new PaginationRepository($paginator);
});
}
/**
* Register the application services.
*
* @return void
*/
public function register()
{
$this->app->singleton('FrontRepository', function($app){
return new \App\Repositories\front\FrontRepository();
});
}
}
好了,这样就大功告成了~
本文学习知识来源:https://www.insp.top/article/replace-laravel-pagination-default-template , 感谢作者的分享。
个人博客地址:http://www.iwanli.me