laravelでAPI作って、フロントはvue.js+axios(非同期なajax)で、SPAなCRUDアプリを作ってみた(前編)
参考URL:
https://qiita.com/minato-naka/items/2d2def4d66ec88dc3ca2
1, laravel本体をインストール。laravel/uiでvueをインストール
2, SPAのために、vue-routerをインストール
3, どんなURLでも、同じページ(app.blade.php)に行くようにルーティングを指定する。
4, コンポーネント(vueの画面パーツ)は、resources/js/components/フォルダにガンガン作っていく
共通ヘッダ・一覧・詳細・更新・新規作成の画面(ハリボテ状態)
5, DB設定はMySQLではなくSQLite
6, laravelでCRUDなREST APIを作る
7, ハリボテだった画面コンポーネントからAPIをaxios(ajax)経由でコールする。
作ってみた感想としては、削除は画面遷移しないのでスムーズだけど、それ以外は対して変わらない(一覧表示とか遅い)
リアルタイムチャットみたいにサーバプッシュな処理がないと、有り難みないな~。
1, laravel本体をインストール。laravel/uiでvueをインストール
2, SPAのために、vue-routerをインストール
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # laravel本体をインストール composer create-project --prefer-dist laravel/laravel vue-laravel-spa cd vue-laravel-spa # uiというフロントエンド開発用のツールをインストール composer require laravel/ui # uiを使って、bootstrap、jquery、vueをpackage.jsonに追記 php artisan ui vue # 実際にnodeパッケージをインストールする。node_modulesに格納 npm install # SPA用にVue Routerをインストール npm install --save vue-router # フロントエンドをビルドする npm run dev | 
/public/js/app.jsと/public/css/app.cssが生成される。
git管理外にするために、.gitignoreに記述しておく
/public/js
/public/css
この時点では下準備(パッケージのインストール)が整っただけで、ブラウザの見た目は何も変わっていない。
php artisan serve
ここからVue-RouterでSPAを作る。
3, どんなURLでも、同じページ(app.blade.php)に行くようにルーティングを指定する。
最初からあるExample Componentを表示する。
| 1 2 3 4 5 6 | // Route::get('/', function () { //     return view('welcome'); // }); Route::get('/{any}', function() {     return view('app'); })->where('any', '.*'); | 
SPAとなる、resources/view/app.blade.phpを作成
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <!doctype html> <html lang="{{ str_replace('_', '-', app()->getLocale()) }}"> <head>     <meta charset="utf-8">     <meta name="viewport" content="width=device-width, initial-scale=1">     <!-- CSRF Token -->     <meta name="csrf-token" content="{{ csrf_token() }}">     <title>{{ config('app.name', 'Vue Laravel SPA') }}</title>     <!-- Styles -->     <link href="{{ mix('/css/app.css') }}" rel="stylesheet"> </head> <body> <div id="app">   <example-component></example-component> </div> <!-- Scripts --> <script src="{{ mix('/js/app.js') }}" defer></script> </body> </html> | 
http://127.0.0.1:8000/abc など適当なURLを入力しても、404エラーにならず、全て同じ表示になる。
4, コンポーネント(vueの画面パーツ)は、resources/js/components/フォルダにガンガン作っていく
ExampleComponent.vueだけ最初からある。
共有ヘッダ(HeaderComponent.vue)
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <template>     <div class="container-fluid bg-dark mb-3">         <div class="container">             <nav class="navbar navbar-dark">                 <span class="navbar-brand mb-0 h1">Vue Laravel SPA</span>                 <div>                     <button class="btn btn-success">List</button>                     <button class="btn btn-success">ADD</button>                 </div>             </nav>         </div>     </div> </template> <script>     export default {} </script> | 
ブラウザ画面に表示させるには
resources/js/app.jsにimportする
| 1 2 3 4 5 6 7 8 9 10 11 12 | + import HeaderComponent from "./components/HeaderComponent"; //↑ファイル先頭   Vue.component('example-component', require('./components/ExampleComponent.vue').default); + Vue.component('header-component', HeaderComponent); コンポーネントを差し替え resources/views/app.blade.php  <div id="app"> -     <example-component></example-component> +     <header-component></header-component>  </div> | 
npm run devするか、npm run watchしっぱなしで、リビルドするとブラウザ表示が変わってヘッダ・コンポーネントが表示される。
メイン部分のコンポーネント作成
resources/js/components/TaskListComponent.vue
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | <template>     <div class="container">         <table class="table table-hover">             <thead class="thead-light">             <tr>                 <th scope="col">#</th>                 <th scope="col">Title</th>                 <th scope="col">Content</th>                 <th scope="col">Person In Charge</th>                 <th scope="col">Show</th>                 <th scope="col">Edit</th>                 <th scope="col">Delete</th>             </tr>             </thead>             <tbody>             <tr>                 <th scope="row">1</th>                 <td>Title1</td>                 <td>Content1</td>                 <td>Ichiro</td>                 <td>                     <button class="btn btn-primary">Show</button>                 </td>                 <td>                     <button class="btn btn-success">Edit</button>                 </td>                 <td>                     <button class="btn btn-danger">Delete</button>                 </td>             </tr>             <tr>                 <th scope="row">2</th>                 <td>Title2</td>                 <td>Content2</td>                 <td>Jiro</td>                 <td>                     <button class="btn btn-primary">Show</button>                 </td>                 <td>                     <button class="btn btn-success">Edit</button>                 </td>                 <td>                     <button class="btn btn-danger">Delete</button>                 </td>             </tr>             <tr>                 <th scope="row">3</th>                 <td>Title3</td>                 <td>Content3</td>                 <td>Saburo</td>                 <td>                     <button class="btn btn-primary">Show</button>                 </td>                 <td>                     <button class="btn btn-success">Edit</button>                 </td>                 <td>                     <button class="btn btn-danger">Delete</button>                 </td>             </tr>             </tbody>         </table>     </div> </template> <script>     export default {} </script> | 
作成したメイン部分のコンポーネントとvue-routerをインポートする
resources/js/app.js
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | // SPA用ルータ import VueRouter from 'vue-router'; import HeaderComponent from "./components/HeaderComponent"; // メイン部分のコンポーネント import TaskListComponent from "./components/TaskListComponent";   window.Vue = require('vue'); // Vueルータの定義 Vue.use(VueRouter); const router = new VueRouter({     mode: 'history',     routes: [         {             path: '/tasks',             name: 'task.list',             component: TaskListComponent         },     ] }); const app = new Vue({     el: '#app',     router // これを忘れずに! }); | 
app.blade.phpで、vue-routerの表示部分となるを追記(ここがURLパスで切り替わる)
| 1 2 3 4 | <div id="app">   <header-component></header-component>   <router-view></router-view> </div> | 
これで /tasks だけはタスク一覧が表示されるようになった。
http://localhost:8000/tasks
ヘッダボタンのリンクを作っておく
resources/js/components/HeaderComponent.vue
| 1 2 3 4 5 6 | <div>     <router-link v-bind:to="{name: 'task.list'}">       <button class="btn btn-success">List</button>     </router-link>     <button class="btn btn-success">ADD</button> </div> | 
タスクの詳細ページのコンポーネントを作成
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | resources/js/components/TaskShowComponent.vue <template>     <div class="container">         <div class="row justify-content-center">             <div class="col-sm-6">                 <form>                     <div class="form-group row border-bottom">                         <label for="id" class="col-sm-3 col-form-label">ID</label>                         <input type="text" class="col-sm-9 form-control-plaintext" readonly id="id"                                v-bind:value="taskId">                     </div>                     <div class="form-group row border-bottom">                         <label for="title" class="col-sm-3 col-form-label">Title</label>                         <input type="text" class="col-sm-9 form-control-plaintext" readonly id="title"                                value="title title">                     </div>                     <div class="form-group row border-bottom">                         <label for="content" class="col-sm-3 col-form-label">Content</label>                         <input type="text" class="col-sm-9 form-control-plaintext" readonly id="content"                                value="content content">                     </div>                     <div class="form-group row border-bottom">                         <label for="person-in-charge" class="col-sm-3 col-form-label">Person In Charge</label>                         <input type="text" class="col-sm-9 form-control-plaintext" readonly id="person-in-charge"                                value="Ichiro">                     </div>                 </form>             </div>         </div>     </div> </template> <script>     export default {         props: {             taskId: String         }     } </script> | 
Vue-Routerに追記
resources/js/app.js
| 1 2 3 4 5 6 7 8 9 | // タスク詳細画面 import TaskShowComponent from "./components/TaskShowComponent"; {     path: '/tasks/:taskId',     name: 'task.show',     component: TaskShowComponent,     props: true }, | 
詳細画面がブラウザ表示されるようになる。
http://localhost:8000/tasks/3
タスク一覧画面の詳細ボタンのリンクを修正
resources/js/components/TaskListComponent.vue
| 1 2 3 4 5 6 7 8 9 10 11 12 13 |     <router-link v-bind:to="{name: 'task.show', params: {taskId: 1}}">        <button class="btn btn-primary">Show</button>     </router-link>     <router-link v-bind:to="{name: 'task.show', params: {taskId: 2}}">        <button class="btn btn-primary">Show</button>     </router-link>     <router-link v-bind:to="{name: 'task.show', params: {taskId: 3}}">        <button class="btn btn-primary">Show</button>     </router-link> | 
登録・修正のWebフォームだけ作って、中身の処理は無し!
タスク登録コンポーネント
resources/js/components/TaskCreateComponent.vue
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <template>     <div class="container">         <div class="row justify-content-center">             <div class="col-sm-6">                 <form>                     <div class="form-group row">                         <label for="title" class="col-sm-3 col-form-label">Title</label>                         <input type="text" class="col-sm-9 form-control" id="title">                     </div>                     <div class="form-group row">                         <label for="content" class="col-sm-3 col-form-label">Content</label>                         <input type="text" class="col-sm-9 form-control" id="content">                     </div>                     <div class="form-group row">                         <label for="person-in-charge" class="col-sm-3 col-form-label">Person In Charge</label>                         <input type="text" class="col-sm-9 form-control" id="person-in-charge">                     </div>                     <button type="submit" class="btn btn-primary">Submit</button>                 </form>             </div>         </div>     </div> </template> <script>     export default {} </script> | 
app.jsにルーティング追加
| 1 2 3 4 5 | {     path: '/tasks/create',     name: 'task.create',     component: TaskCreateComponent }, | 
共通ヘッダに作成画面へのリンクボタン
| 1 2 3 |     <router-link v-bind:to="{name: 'task.create'}">        <button class="btn btn-success">ADD</button>     </router-link> | 
タスク編集画面も作っておく
resources/js/components/TaskEditComponent.vue
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | <template>     <div class="container">         <div class="row justify-content-center">             <div class="col-sm-6">                 <form>                     <div class="form-group row">                         <label for="id" class="col-sm-3 col-form-label">ID</label>                         <input type="text" class="col-sm-9 form-control-plaintext" readonly id="id" v-bind:value="taskId">                     </div>                     <div class="form-group row">                         <label for="title" class="col-sm-3 col-form-label">Title</label>                         <input type="text" class="col-sm-9 form-control" id="title">                     </div>                     <div class="form-group row">                         <label for="content" class="col-sm-3 col-form-label">Content</label>                         <input type="text" class="col-sm-9 form-control" id="content">                     </div>                     <div class="form-group row">                         <label for="person-in-charge" class="col-sm-3 col-form-label">Person In Charge</label>                         <input type="text" class="col-sm-9 form-control" id="person-in-charge">                     </div>                     <button type="submit" class="btn btn-primary">Submit</button>                 </form>             </div>         </div>     </div> </template> <script>     export default {         props: {             taskId: String         }     } </script> | 
app.jsにルーティング追加
| 1 2 3 4 5 6 | {     path: '/tasks/:taskId/edit',     name: 'task.edit',     component: TaskEditComponent,     props: true }, | 
ボタン表示部分も修正。
| 1 2 3 |     <router-link v-bind:to="{name: 'task.edit', params: {taskId: 3}}">         <button class="btn btn-success">Edit</button>     </router-link> | 
長くなってきたので、後編へ~。