【Laravel10 + Vue3】vuejs-paginate-nextでページネーションを実装

Laravel

Laravel10 + Vue3 で、vuejs-paginate-next コンポーネントを使ってPaginationを実装していきます。

vuejs-paginate-next
A simple Vue3 pagination component.. Latest version: 1.0.2, last published: 2 years ago. Start using vuejs-paginate-next...

前提条件

  • Ubuntu上で作業しています
  • PHP8.2以降インストール済
  • Composer v2以降インストール済

これからやること

  • 環境構築(Laravel10 + Vue3 + vuejs-paginate-next)
  • マイグレーション
  • API作成
  • ルーティング(API)
  • ブラウザ確認(API)
  • Vueコンポーネント編集
  • ブラウザ確認

環境構築(Laravel10 + Vue3 + vuejs-paginate-next)

Laravel10プロジェクト「pagination-vue3」を作成します。

composer create-project laravel/laravel:^10 pagination-vue3

「pagination-vue3」フォルダに入って、

viteプラグインのvue3をインストールします。

npm install @vitejs/plugin-vue --save-dev

プロジェクトトップにある「vite.config.js」にvueの設定を追記します。

import vue from "@vitejs/plugin-vue"
        vue(),

Vue3用のページネーションコンポーネントvuejs-paginate-nextをインストールします。

vuejs-paginate-next
A simple Vue3 pagination component.. Latest version: 1.0.2, last published: 2 years ago. Start using vuejs-paginate-next...
npm install vuejs-paginate-next --save

「resources/js/app.js」にVue3とvuejs-paginate-nextの設定を追記します。

追記する内容:

import {createApp} from 'vue'
import Paginate from "vuejs-paginate-next";
import App from './App.vue'
createApp(App).use(Paginate).mount("#app")

同じフォルダ内に「App.vue」ファイルを作成して編集・保存します。

<template>
    <div>
        <paginate
            :page-count="20"
            :page-range="3"
            :margin-pages="2"
            :click-handler="clickCallback"
            :prev-text="'Prev'"
            :next-text="'Next'"
            :container-class="'pagination'"
            :page-class="'page-item'"
        >
        </paginate>
    </div>
</template>

<script>
import Paginate from 'vuejs-paginate-next';
export default {
    components: {
      paginate: Paginate,
    },
    methods: {
      clickCallback (pageNum) {
        console.log(pageNum)
      }
    },
}
</script>

<style lang="css">
  @import "https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css";
</style>

ビューファイルを作成します。

php artisan make:view users

「resources/vies/users.blade.php」を編集・保存します。


<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Laravel Vite Vue</title>
        @vite(['resources/css/app.css', 'resources/js/app.js'])
    </head>
    <body>
        <div id="app"></div>
    </body>
</html>

「routes/web.php」を開いてルーティングを追記します。

Route::get('/users', function () {
    return view('users');
});

WEBサービスを起動して一度表示確認してみましょう。

まずはviteを起動します。

npm run dev

別のターミナルでlaravelのWEBサービスを起動します。

php artisan serve

WEBブラウザで「http://127.0.0.1:8000/users」にアクセスします。

ページネーションが表示されました。bootstrap5のスタイルを適用しています。

ページリンクをクリックした際のコールバックにより、

コンソールにページ番号が表示されています。

このページネーションはガワだけなので、ページリンクをクリックした際の挙動を実装していく必要があります。

マイグレーション

プロジェクトトップにある「.env」を編集します。

DB_CONNECTION=sqlite

に修正して、それ以外のDB項目を削除します。

「database/seeders/DatabaseSeeder.php」を編集します。

        // \App\Models\User::factory(10)->create();

の箇所を修正します。

        \App\Models\User::factory(150)->create();

シーダーオプション付きでマイグレーションを実行します。

php artisan migrate --seed

SQLiteのファイルを作成するか訊かれるので、

[←]キーを押して「Yes」を選択し[Enter]で確定します。

ユーザーデータが150件生成されています。

API作成

API用のコントローラーを作成します。

php artisan make:controller Api/UsersController

「app/Http/Controllers/Api/UsersController.php」

を開いて編集・保存します。

<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\User;

class UsersController extends Controller
{
    public function index(Request $request)
    {
        $perPage = $request->query('perPage') ?? 10;
        $domain = $request->query('domain') ?? '';
        $orderbyID = strcmp($request->query('orderbyID'), 'desc') === 0
                   ? 'desc'
                   : 'asc';
        $users = User::where('email', 'LIKE', '%' . $domain)
                    ->orderby('id', $orderbyID)
                    ->paginate($perPage);
        $empty = User::selectRaw("''");
        $domains = User::selectRaw(
                    "substr(email, instr(email,'@'), length(email))
                    as domain"
                   )
                   ->union($empty)
                   ->distinct()
                   ->orderby('domain', 'asc')
                   ->get();
        $status = 200;
        $message = 'Retrieving Users Succeeded.';
        return [
            'status' => $status,
            'message' => $message,
            'users' => $users,
            'domains' => $domains,
            'selectedDomain' => $domain,
            'perPages' => [5, 10, 20, 50, ],
            'orderbyID' => $orderbyID,
        ];
    }
}

このコントローラーは以前の記事で作成したコントローラーをAPIに転用したものです。

ルーティング(API)

「routes/api.php」を開いて追記します。

Route::get('/users', [\App\Http\Controllers\Api\UsersController::class, 'index']);

ブラウザ確認(API)

WEBブラウザで

http://127.0.0.1:8000/api/users

にアクセスします。

ユーザーデータのページネーションの結果がJSON形式で表示されています。

Vueコンポーネント編集

先程作成したApp.vueでAPIからJSONを取得し、

ページリンクをクリックした際のコールバックで

ユーザー一覧を表示切替できるようにしていきます。

<template>
    <div>
        <paginate
            v-model="currentPage"
            :page-count="pageCount"
            :page-range="3"
            :margin-pages="2"
            :click-handler="clickCallback"
            :prev-text="'<'"
            :next-text="'>'"
            :container-class="'pagination'"
            :page-class="'page-item'"
        >
        </paginate>
        絞り込み:ドメイン<select v-model="domain" @change="changeDomain">
          <option v-for="d in domains" :value="d.domain">{{ d.domain.length > 0 ? d.domain : '指定しない' }}</option>
        </select>
        表示件数<select v-model="perPage" @change="changePerPage">
          <option v-for="p in perPages" :value="p">{{ p }}</option>
        </select>件/ページ<br>
        並び順:ID<select v-model="orderbyID" @change="changeOrderbyID">
          <option v-for="o in orderbyIDs" :value="o">{{ orderbyIDText[o] }}</option>
        </select>
        <ul class="users">
          <li v-for="u in users.data" class="user">{{ u.id }}: {{ u.name }} &lt;{{ u.email }}&gt;</li>
        </ul>
    </div>
</template>

<script>
import Paginate from 'vuejs-paginate-next';
export default {
    components: {
      paginate: Paginate,
    },
    data () {
      return {
        perPage: 10,
        pageCount: 1,
        currentPage: 1,
        users: [],
        domains: [],
        perPages: [],
        domain: '',
        orderbyID: 'asc',
        orderbyIDs: ['asc', 'desc'],
        orderbyIDText: {asc: '昇順', desc: '降順'},
        apiBase: location.protocol + '//' + location.host + '/api/users'
      }
    },
    methods: {
      apiUrl (pageNum, perPage, domain, orderbyID) {
        return this.apiBase
               + '?page=' + pageNum
               + '&perPage=' + perPage
               + '&domain=' + domain
               + '&orderbyID=' + orderbyID;
      },
      async fetchUsers (pageNum, perPage, domain, orderbyID) {
        const url = this.apiUrl(pageNum, perPage, domain, orderbyID);
        const res = await fetch(url);
        const json = await res.json();
        this.users = json.users;
        this.domains = json.domains;
        this.perPages = json.perPages;
        this.pageCount = json.users.last_page;
      },
      clickCallback (pageNum) {
        this.fetchUsers(pageNum, this.perPage, this.domain, this.orderbyID);
        this.currentPage = pageNum;
      },
      changeDomain () {
        this.fetchUsers(1, this.perPage, this.domain, this.orderbyID);
        this.currentPage = 1;
      },
      changePerPage () {
        this.fetchUsers(1, this.perPage, this.domain, this.orderbyID);
        this.currentPage = 1;
      },
      changeOrderbyID () {
        this.fetchUsers(this.currentPage, this.perPage, this.domain, this.orderbyID);
      }
    },
    mounted () {
      this.fetchUsers(this.currentPage, this.perPage, this.domain, this.orderbyID);
    }
}
</script>

<style lang="css">
  @import "https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css";
</style>

ブラウザ確認

WEBブラウザで

http://127.0.0.1:8000/users

にアクセスします。

ページネーション、絞り込み条件、並び順、ユーザー一覧が表示されました。

絞り込み条件や並び順、ページを変更してみます。

しっかり反映されています。

今回はここまでです。お疲れさまでした。

続きはこちら。

コメント

タイトルとURLをコピーしました