Laravel 5.6如何实现无插件的优雅URL(Pretty URL)分页?
Absolutely! You're right that Laravel's native pagination defaults to using query strings like ?page=2, but we can totally implement clean, pretty URLs (e.g., /posts/page/2) without any third-party packages. Let's walk through the process step by step:
1. Set Up Custom Routes
First, we need to add routes that handle the pretty pagination structure. Open your routes/web.php file and add these routes (adjust the controller and path to match your application):
// Handle the first page (without the /page/1 segment) Route::get('/posts', [PostController::class, 'index'])->name('posts.index'); // Handle pages 2 and beyond with the pretty URL structure Route::get('/posts/page/{page}', [PostController::class, 'index'])->name('posts.index.page');
2. Modify Your Controller Logic
Next, update your controller method to accept the page parameter, fetch the appropriate data, and customize the paginator's URL generation behavior. You have two straightforward approaches:
Option A: Tweak the Built-in Paginator (Simpler)
If you're using Laravel's query builder or Eloquent paginate() method, you can override the URL resolver to generate pretty links directly:
use App\Models\Post; public function index($page = 1) { // Validate the page parameter to block invalid requests if (!is_numeric($page) || $page < 1) { abort(404); } // Fetch paginated data as usual, passing the current page $posts = Post::paginate(10, ['*'], 'page', $page); // Override the URL resolver to generate pretty links $posts->setUrlResolver(function ($pageNumber) { if ($pageNumber === 1) { // For the first page, use the root route (no /page/1 segment) return route('posts.index', request()->except('page')); } // For other pages, use the pretty URL route and preserve any existing query params return route('posts.index.page', array_merge( ['page' => $pageNumber], request()->except('page') )); }); return view('posts.index', compact('posts')); }
Option B: Manually Create a Paginator (More Control)
If you need full control over the pagination logic, create a LengthAwarePaginator instance manually:
use App\Models\Post; use Illuminate\Pagination\LengthAwarePaginator; public function index($page = 1) { $perPage = 10; $offset = ($page - 1) * $perPage; $totalPosts = Post::count(); // Validate page number to avoid out-of-bounds requests if (!is_numeric($page) || $page < 1 || $offset >= $totalPosts) { abort(404); } // Fetch the relevant slice of data $posts = Post::skip($offset)->take($perPage)->get(); // Create the paginator instance $paginator = new LengthAwarePaginator( $posts, $totalPosts, $perPage, $page, ['pageName' => 'page'] ); // Set up the URL resolver for pretty links $paginator->setUrlResolver(function ($pageNumber) { $queryParams = request()->except('page'); if ($pageNumber === 1) { return route('posts.index', $queryParams); } return route('posts.index.page', array_merge(['page' => $pageNumber], $queryParams)); }); return view('posts.index', compact('paginator')); }
3. Render Pagination in Your View
You can use Laravel's standard pagination blade directives just like you normally would. For example, in your posts/index.blade.php:
<div class="pagination"> {{ $posts->links() }} </div>
The paginator will now generate links like /posts for the first page, /posts/page/2 for the second, and so on—all without any third-party packages.
Bonus: Handle Additional Query Parameters
If your page uses query parameters (like search filters), the code above already preserves them by merging request()->except('page') into the route parameters. So if you have a URL like /posts?search=laravel, the pagination links will become /posts/page/2?search=laravel—keeping your filters intact while maintaining pretty pagination URLs.
内容的提问来源于stack exchange,提问作者Jesse

