1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Laravel6.x + Vue.js(TypeScript)のSPAでページネーション付きのテーブル作成

Last updated at Posted at 2020-05-20

冒頭

  • 個人開発でLaravel6.x + Vue.js(TypeScript)のSPA作ったので一部抜粋
  • CSSフレームワークはVuetify2を採用
  • 環境構築については一旦スルーします
  • ソースコード例はこちら

ディレクトリ構造

フロント側の構造のみ抜粋

resources/ts
├── App.vue
├── app.ts
├── components
│   └── pages
│       └── Search.vue
├── laravel-data-entity
│   └── PaginateObject.d.ts
├── plugins
│   └── http.ts
├── router.ts
├── types
│   └── index.d.ts
└── vue-data-entity
    └── DataObject.d.ts

ソースコード

型定義ファイル

  • データベースのテーブルに用意してるテーブルの構造を定義する
resources/ts/vue-data-entity/DataObject.d.ts
export interface FileDataObject {
  id: number;
  hoge: string;
}
  • Laravelのページネーションオブジェクトを定義する
resources/ts/laravel-data-entity/PaginateObject.d.ts
import { DataObject } from "../vue-data-entity/FDataObject"

export interface PaginateObject {
  current_page: number;
  data: DataObject[];
  first_page_url: string;
  from: number;
  last_page: number;
  last_page_url: string;
  next_page_url: string;
  path: string;
  per_page: number;
  prev_page_url: string | null;
  to: number;
  total: number;
}

Vue Routerの設定

resources/ts/router.ts
import Vue from 'vue'
import Router from 'vue-router'
import Search from './components/pages/Search.vue'
Vue.use(Router)

const router = new Router({
  mode: 'history',
  routes: [
    {
      path: '/search',
      name: 'Search',
      component: Search,
    },
  ]
});
export default router;

Axiosをラップしたプラグインを作る

resources/ts/plugins/http.ts
import _Vue from 'vue';
import axios from 'axios';

export default {
  install(Vue: typeof _Vue): void {
    const http = axios.create({
      responseType: "json"
    });
    Vue.prototype.$http = http;
  },
};

プラグインをインストール、ルーターを設定

resources/ts/app.ts
import Vue from "vue";
import router from './router'
import App from "./App.vue";
~~省略~~
import http from './plugins/http';

Vue.use(http);

~~省略~~

new Vue({
  router: router,
  render: h => h(App),
~~省略~~
}).$mount('#app')

Vue側のソースコード例

resources/ts/components/pages/Search.vue
<template>
  <v-content>
    <v-container fluid>
      <v-simple-table dense>
        <template v-slot:default>
          <thead>
            <tr>
              <th class="text-left">id</th>
              <th class="text-left">hoge</th>
            </tr>
          </thead>
          <tbody>
            <tr v-for="(item, index) in data" :key="index">
              <td>{{ item.id }}</td>
              <td>{{ item.hoge }}</td>
            </tr>
          </tbody>
        </template>
      </v-simple-table>
      <v-pagination v-model="page" :length="pageLength"></v-pagination>
    </v-container>
    <v-overlay :value="overlay">
      <v-progress-circular color="primary" indeterminate size="64"></v-progress-circular>
    </v-overlay>
  </v-content>
</template>

<script lang="ts">
import { DataObject } from "../../vue-data-entity/DataObject";
import { PaginateObject } from "../../laravel-data-entity/PaginateObject";
import { Vue, Component, Watch } from "vue-property-decorator";
import VueRouter from "vue-router";
import { AxiosError, AxiosResponse } from "axios";

// registerHooksを登録しないとbeforeRouteUpdateが定義できません
Component.registerHooks(["beforeRouteUpdate"]);
export default class Search extends Vue {
  data: FileDataObject[] = [];
  overlay: boolean = false;
  pageLength: number = 1;
  page: number = 1;

  /**
   * created
   */
  public created() {
    this.search();
  }

  /**
   * watch
   * ルーティングに反映するためにWatchを使います。
   */
  @Watch("page")
  onPageChanged() {
    this.$router
      .push({
        name: "Search",
        query: {
          page: this.page.toString()
        }
      })
  }


  /**
   * search
   */
  public search() {
    this.page = isNaN(Number(this.$route.query.page))
      ? 1
      : Number(this.$route.query.page);
    this.overlay = true;
    Vue.prototype.$http
      .get(
        `/api/search?page=${this.page}`
      )
      .then((res: AxiosResponse<PaginateObject>): void => {
        this.data = res.data.data;
        this.pageLength = res.data.last_page;
        this.overlay = false;
      })
      .catch((error: AxiosError): void => {
        alert("検索実行時にエラーが発生しました");
        this.overlay = false;
      });
  }

  /**
   * beforeRouteUpdate
   * ルーティングが更新される毎に(this.pageが変更する毎に検索を実行します)
   */
  public beforeRouteUpdate(to: VueRouter, from: VueRouter, next: any) {
    next();
    this.search();
  }

}
</script>
resources/ts/App.vue
<template>
  <v-app id="inspire">
    <router-view />
  </v-app>
</template>

Laravel側

APIのルーティングを定義

routes/api.php
Route::get('search', 'Api\SearchController@search');

APIのコントローラーでページネーションオブジェクトを返却する

app/Http/Controllers/Api/SearchController.php
<?php

namespace App\Http\Controllers\Api;

use App\Data; //モデルを定義しといてね
use App\Http\Controllers\Controller;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;

class SearchController extends Controller
{
    /**
     *
     *
     * @return
     */
    public function search(Request $request)
    {
        return Data::select('id', 'hoge')->paginate(10);
    }
}
resources/views/index.blade.php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
  <head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# website: http://ogp.me/ns/website#">
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <meta name="robots" content="index,follow">
    <title>~~~~</title>
  </head>
    <body>
      <div id="app" >
      </div>
      <script src="{{ mix('/js/app.js') }}"></script>
    </body>
</html>

##動作例

n9o60-s67f1.gif

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?