ソリューション技術部の近藤(id:kazumeat)です。主にWebアプリ開発をしています。
Vue.jsで管理システムを構築しているときに、さくっと検索結果一覧画面が作れないかなと思って 色々コンポーネントを探していた時に見つけたVuetable-2の紹介です。
以下の点を条件として探しました。
- デザイン(css)を独自に当てることができること
- ページングができること
- ページングした時に、サーバにアクセスし、対象のデータだけ取得すること
Vuetable-2
特定のデザインで構成されているわけではないため、すでにデザインが決まっているページでも 簡単に導入することができます。 もちろん、各種CSSフレームワークとの連携も可能です。 Vuetable-2の作者の方が公開されているSandboxではsemantic-uiを使用しています。 下記サンプルのような感じで、結構色々と機能があり、カスタマイズもできます。 タイトルに[WIP]と付いていますが、一通り動作しています。
Vuetable-2の日本語の紹介記事はこちら。日本語記事が全然ないので貴重です。 こちらの記事ではLaravelでの実装部分も記載されています。
LaravelとVuetable-2でページネーション付きテーブルを使ってみる - Qiita
Vue-tables-2
ちなみに、名前が激似の別コンポーネントが存在しますが、こちらはVuetable-2
とは全くの関係ないのでご注意を。
matfish2/vue-tables-2: Vue.js 2 grid components
下記紹介記事にもある通り、全件データを取得した後は、クライアントで完結する形のテーブル表示コンポーネントです。 そこまでデータ数が多くない場合は使ってみてもいいかもしれないですね。
Vuejsでテーブル表示 vue-tables-2 - Qiita
検索結果一覧を実装する
いわゆる、検索条件を入力し、検索ボタンをクリックすると、検索結果がページング付きのテーブルで表示される、という画面を作ります。 こんな画面です。
解説内容としては、Vuetable-2の紹介のみとなります。
- バックエンドはLaravel
- Laravelである必要は全くありませんが、親和性が高いです。
- 検索結果データを取得するAPIを実装します
- フロントエンドはVue.js
Dockerで開発環境を作る
まずはVue.jsで開発するための環境を作ります。
Dockerfile
FROM node:10.11.0-alpine RUN apk update && \ apk add git && \ yarn global add @vue/cli ENV HOST 0.0.0.0 WORKDIR /app
docker-compose.yml
version: '3' services: vuetable-2-demo: tty: true privileged: true volumes: - .:/app ports: - 8080:8080 container_name: demo
各種バージョン
/app # node -v v10.11.0 /app # yarn -v 1.9.4 /app # vue -V 3.0.5
vue.jsのアプリを新規に作成します
/app # vue create vuetable-demo <設定はデフォルト> /app # cd vuetable-demo /app # yarn install /app # yarn serve
http://localhost:8080 にアクセスしてVue.jsのホーム画面表示を確認
vuetable-2をインストール
- インストール
/app/vuetable-demo # yarn install vuetable-2@next
- vuetable-2は、現時点で最新の下記バージョンを使用します。
info Direct dependencies └─ vuetable-2@2.0.0-beta.3
Laravelでデータ取得API作成
Laravelでの具体的なAPI実装方法は割愛しますが、Vuetable-2はLaravelのPaginateメソッドが吐き出すJson形式をそのまま使うことができます。
参考:https://readouble.com/laravel/5.5/ja/pagination.html
{ "total": 50, "per_page": 15, "current_page": 1, "last_page": 4, "first_page_url": "http://laravel.app?page=1", "last_page_url": "http://laravel.app?page=4", "next_page_url": "http://laravel.app?page=2", "prev_page_url": null, "path": "http://laravel.app", "from": 1, "to": 15, "data":[ { // 結果のオブジェクト }, { // 結果のオブジェクト } ] }
こちらのJsonをカスタマイズなしに、Vuetable-2に食わせることができます。 もちろんLaravelを使わずとも、このJson形式でなくとも、Json形式はカスタマイズして食わせることもできますのでご安心を。
vuetable-2/Data-Transformation.md at master · ratiw/vuetable-2
Vuetable-2を使ってみる
Vue.jsでの実装に戻ります。
Vuetable-2コンポーネントを設置
各種プロパティの説明はこちらにあります。
https://ratiw.github.io/vuetable-2/#/Vuetable-Properties
List.vue
- 検索条件入力部分のコードは割愛します
- Vuetable-2コンポーネントを設置します
- 以下は今回私が使用したプロパティになります
<template> <div> <vuetable ref="vuetable" :api-url="https://hogehoge/api" :http-fetch="myFetch" :fields="fields" :append-params="moreParams" pagination-path="" @vuetable:pagination-data="onPaginationData" > </vuetable> <vuetable-pagination ref="pagination" @vuetable-pagination:change-page="onChangePage" > </vuetable-pagination> </div> </template> <script> import axios from 'axios' import {Vuetable, VuetablePagination} from 'vuetable-2' import FieldsDef from "~/components/FieldsDef.js"; export default { components: { Vuetable, VuetablePagination, }, data () { return { fields: FieldsDef, // テーブルの項目は別ファイルに定義 moreParams: {sort: 'created_at', order: 'desc'} //後述 } }, methods: { myFetch (apiUrl, httpOptions) { return this.$axios.get(apiUrl, httpOptions); }, onSearch () { this.$nextTick(function() { this.$refs.vuetable.refresh(); //:http-fetchに設定されたmethod(myFetch)が呼ばれる(後述) }); }, onPaginationData (paginationData) { this.$refs.pagination.setPaginationData(paginationData); }, onChangePage (page) { this.$refs.vuetable.changePage(page); } } } </script>
components/FieldsDef.js
- テーブルに必要な列を定義しているファイルです
- hiddenフィールド(visible: false)を追加したり、フォーマットしたり、ボタンを設置するための列を追加したりしてます
export default [ { name: 'id', visible: false }, { name: 'number', title: '番号' }, { name: 'amount', title: '金額', sortField: 'amount', formatter (value) { if(value) { return value.toLocaleString()+'円'; } }, }, { name: 'date', title: '日時', sortField: 'date', formatter (value) { if(value) { return moment(value).format("YYYY/MM/DD HH:mm"); } }, }, { name: 'status', title: 'ステータス', sortField: 'status' }, { name: 'canceled_at', title: '取消日時', sortField: 'canceled_at', formatter (value) { if(value) { return moment(value).format("YYYY/MM/DD HH:mm");[f:id:kazumeat:20181010174454j:plain] } }, }, { name: 'actions', //編集ボタンなどを表示する列 title: '' } ]
Vuetable-2プロパティ
以下、サンプルでは使用されていなかったプロパティを紹介します。
http-fetch
今回実際にアクセスするAPIには、トークンの指定が必要でした。
そのため、Vuetable-2でAPIにアクセスする前にひと手間必要になります。
http-fetch
にはひと手間の処理を追加するためのメソッドを指定します。(myFetch)
そこで、アクセスヘッダーにトークンをセットします。
methods: { myFetch (apiUrl, httpOptions) { // APIリクエスト時にトークンを付与する this.$axios.onRequest(config => { config.headers.common['Content-Type'] = 'application/json'; if (this.$store.state.token) { config.headers.common['Authorization'] = 'Bearer ' + this.$store.state.token; } }); return this.$axios.get(apiUrl, httpOptions); }, onSearch () { this.$nextTick(function() { this.$refs.vuetable.refresh(); //:http-fetchに設定されたmethod(myFetch)が呼ばれる }); }, },
APIを呼ぶトリガーとしては検索ボタンを用意し、ボタンがクリックされるとonSearch
メソッドが呼ばれます。
append-params
今回は検索条件もAPIパラメータに付与したかったので、こちらもひと手間を加えるために
append-params
でデータを追加しています。
methods: { onSearch () { this.moreParams = {sort: 'created_at', order: 'desc', status: 'hoge'}; // <- 動的に検索条件などを付与する this.$nextTick(function() { this.$refs.vuetable.refresh(); }); } },
ページングコンポーネント、表示上のバグ
vuetable-2@2.0.0-beta.3 には、ページングコンポーネント部分にバグがあります。 例えば、ページは10ページまでしかないのに、11、12ページが見た目上できてしまうバグです。クリックしても何も起こらず、その他の機能については問題なく動作するため、影響的には低いです。すでにissueが上がっていますが、まだ取り込まれていないのでご注意ください。
https://github.com/ratiw/vuetable-2/pull/515
公式チュートリアル
Vuetable-2の作者の方が、丁寧にチュートリアルのページを用意してくれています(^^) https://github.com/ratiw/vuetable-2-tutorial/wiki
また、作者のratiwさんはめちゃめちゃ親切な方で、質問に対してはとても丁寧に返答を頂けます。困ったことがあったら質問してみましょう!