Laravel6.xとVue Routerでvue.jsのSPA構築
本文書ではLaravelのバージョン6.xとvue.jsのVue Routerを利用してシングルアプリケーションの構築方法を確認します。アプリケーション内では、ローカルのデータベースに保存したuserテーブルのデータを使います。
本文書を読み終えた後は下記を理解することができます。
- Laravelとvue.jsを連携させたCRUD(create, read, update, delete)の理解
- Vue Routerによるページリロードなしのページ遷移
- Laravelとvue.jsとVue Routerの環境下でのアプリの作成の基礎
MAC環境で動作確認を行っています。
本文書ではVue Routerの基本はわかっているという前提で進めさせていただきます。Vue Routerについて理解が不足している場合は下記の文書を参考にしてください。
環境の構築
Laravelのインストール
Laravelのインストールはcomposerコマンドで行います。
$ composer create-project --prefer-dist laravel/laravel laravel_vue_router
MAC環境へのLaravelのインストールについては下記の文書で詳細に説明を行っているので参考にしてください。
Vueのインストール
Vueのインストールを行うためにはlaravel/uiパッケージをインストールする必要があります。インストールはcomposerコマンドで行います。
$ cd laravel_vue_router
$ composer require laravel/ui
laravel/uiのパッケージのインストールが完了したら、Vueのインストールを行います。下記のコマンドを実行するとLaravelのログイン機能とVueをインストールすることができます。
$ php artisan ui vue --auth
Vue scaffolding installed successfully.
Please run "npm install && npm run dev" to compile your fresh scaffolding.
Authentication scaffolding generated successfully
インストールのメッセージにしたがいnpmコマンドを実行します。
$ npm install && npm run dev
JavaScript関連のライブラリのインストールとコンパイルが行われます。
Laravelの動作確認
Laravelのインストールが正常に行われたか確認するために開発サーバを起動してブラウザでアクセスします。
$ php artisan serve
Laravel development server started: http://127.0.0.1:8000
ブラウザhttp://127.0.0.1:8000にアクセスして、下記の画面が表示されたらインストールは正常に行われています。ログイン機能もインストールしているので、右上にはLOGINとREGISTERも表示されます。
Vue Routerのインストール
npmコマンドでVue Routerプラグインのインストールを行います。
$ npm install vue-router
+ vue-router@3.1.3
added 1 package from 1 contributor and audited 17169 packages in 13.438s
found 0 vulnerabilities
インストール完了後、Vue Routerプラグインを使用するためimportでモジュールvue-routerを読み込み、Vue.useを使ってVueへの登録を行います。Vue.useの登録はresource¥js¥app.jsファイルの中で行います。
require('./bootstrap');
import Vue from 'vue';
import VueRouter from 'vue-router';
window.Vue = Vue;
Vue.use(VueRouter);
const app = new Vue({
el: '#app',
});
router.jsファイルの作成
ルーティングを記述するrouter.jsファイルをresources¥jsディレクトリの下に作成し、下記を記述します。
import Router from 'vue-router'
import Home from './views/Home.vue'
export default new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'home',
component: Home
},
]
});
vueファイルの作成
次にresource¥jsディレクトリの下にviewsディレクトリを作成し、router.jsファイルで読み込まれているHome.vueファイルを作成します。
Home.vueファイルの中にはh1タグのみ追加します。
<template>
<h1>Home Page</h1>
</template>
Routerの追加
app.jsに作成したrouter.jsファイルをimportしVueインスタンスに追加します。
require('./bootstrap');
import Vue from 'vue';
import VueRouter from 'vue-router';
import router from './router'
window.Vue = Vue;
Vue.use(VueRouter);
const app = new Vue({
el: '#app',
router
});;
ブレードファイルへのVue Routerの設定
Laravel側のルーティングファイルであるweb.phpファイル内では”/”へのアクセスはブレードファイルであるwelcome.blade.phpの中身が表示される設定になっています。ブレードファイルをwelcome.blade.phpから別のファイルに変更することも可能ですが本文書ではそのままwelcome.blade.phpファイルを利用します。
Route::get('/', function () {
return view('welcome');
});
resources¥views¥welcome.blade.phpファイルを開いてVue Routerタグであるrouter-link, router-viewタグを設定します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>Example</title>
<link rel="stylesheet" href="{{ mix('css/app.css') }}">
</head>
<body>
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link>
</div>
<router-view/>
</div>
</div>
<script src="{{ mix('js/app.js') }}"></script>
</body>
</html>
ここまでの設定でLaravelとVue Routerを使用するための基本設定は完了したので、ブラウザで確認します。
ブラウザで確認するために更新した内容を自動でコンパイルできるようにnpm run watchコマンドを実行しておきます。
$ npm run watch
確認するとリンクとHome.vueに記述した内容が画面に表示されます。
Vue Routerの設定
ルーティングの追加
router.jsファイル内でのルーティングに新たにaboutページへの設定を追加します。home部分のコードを複製してaboutに変更するだけのシンプルな設定です。About.vueのimportも忘れずに設定を行ってください。
import Router from 'vue-router'
import Home from './views/Home.vue'
import About from './views/About.vue'
export default new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/about',
name: 'about',
component: About
},
]
});
welcome.blade.phpファイルにrouter.jsファイルで追加したaboutを表示させるため、router-linkを追加します。
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link>
<router-link to="/about">About</router-link>
</div>
<router-view/>
</div>
</div>
js¥viewsディレクトリの中にAbout.vueファイルを作成します。
<template>
<h1>About Page</h1>
</template>
追加後ブラウザで確認するとAboutへのページのリンクが表示されます。
Aboutのリンクボタンを押すと画面にAbout Pageが表示されます。
リンクをクリックするのではなく直接URLに127.0.0.1:8000/aboutを入力してアクセスすると404 Not Foundエラーが発生します。
404 Not Foundエラーが表示されるのは、Laravelのルーティングファイルのweb.phpに/aboutへのルーティングについての記述がないためです。404 Not Foundエラーを避けるためweb.phpファイルのルーティングに以下の設定を行います。
Route::get('/{any}', function () {
return view('welcome');
})->where('any','.*');
{any}を設定することで”/”(ルート)以下へのアクセスを行うとwelcome.blade.phpファイルが表示される設定を行っています。しかし{any}だけでは”/”(ルート)へのアクセスがあるとNot Foundエラーが発生します。そのため、where(‘any’,’.*’)も必要になります。
/(ルート)と/about以外のURLにアクセスするとVue Routerのルーティングに対応するルーティングがないのでrouter-view部分が表示されない画面になり、Not Foundエラーは表示されません。例えば以下のように/test/ateaaer/badafといったルーティングが存在しないURLでアクセスを行うと上部にリンクが表示されるだけで中身は何も表示されません。
404エラーページの追加
router.jsファイルに記述させていないURLにアクセスした場合に404エラーを表示させるためには以下の設定を行います。新たにパス”*”(アスタリスク)を追加しそれに対応するvueファイルを設定します。ここではNotFound.vueを指定しています。
import Router from 'vue-router'
import Home from './views/Home.vue'
import About from './views/About.vue'
import NotFound from './views/NotFound.vue'
export default new Router({
mode: 'history',
routes: [
{
path: '*',
component: NotFound
},
{
path: '/',
name: 'home',
component: Home
},
{
path: '/about',
name: 'about',
component: About
},
]
});
resources¥js¥viewsの下にNotFound.vueファイルを作成します。
<template>
<h1>404 Not Found</h1>
</template>
適当なURLを入力してアクセスすると画面に404 Not Foundが表示されます。
データベースの設定
アプリケーションのデータを保存するためにはデータベースが必要となります。ここではsqliteデータベースを利用してデータの保存を行います。
sqliteデータベースの作成
ここではsqliteデータベースを作成するための必須な手順のみ記述しています。より詳しい内容については下記を参考にしてください。
touchコマンドを使ってデータベースファイルの作成を行います。
$ touch database/database.sqlite
.envファイルの編集を行い、MySQL関連の情報を削除して以下のDB_CONNECTIONのみ設定を行います。
DB_CONNECTION=sqlite
設定完了後、php artisan migrateコマンドでテーブルの作成を行います。以下のようにusers, password_resets, failed_jobsテーブルが作成されれば正常に動作しています。
$ php artisan migrate
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table (0.1 seconds)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table (0 seconds)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated: 2019_08_19_000000_create_failed_jobs_table (0 seconds)
Seedingを使ってデータの作成
LaravelのSeeding機能を使って、usersテーブルにダミーデータを挿入します。下記の手順どおりに進めればusersテーブルに50件のダミーデータを挿入することができます。Seeding機能の詳しい内容については下記を参考にしてください。
$ php artisan make:seeder UsersTableSeeder
Seeder created successfully.
database¥seedsの下にUsersTableSeeder.phpファイルが作成されます。ダミーデータを50件作成します。
use Illuminate\Database\Seeder;
class UsersTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$users = factory(App\User::class, 50)->create();
}
}
ダミーデータに入る値の設定はUserFactory.phpで行います。UserFactory.phpはdatabase/factoriesの下に事前に作成されています。今回は初期設定のままで更新を行わないので何もする必要がありません。
次にdatabase/seedsの下にあるDatabaseSeeder.phpファイルのrunのコメントアウトを外します。
public function run()
{
$this->call(UsersTableSeeder::class);
}
設定は完了したので、php artisan db:seedを実行してください。
$ php artisan db:seed
Seeding: UsersTableSeeder
Seeded: UsersTableSeeder (0.36 seconds)
Database seeding completed successfully.
usersテーブルへのデータ挿入は完了です。
usersデータの表示・更新・削除・作成
Laravelのデータベースに保存されているユーザデータをaxiosを利用することで表示・更新・削除・作成を行います。
ルーティングの追加
新たにrouter.jsファイルにパス/userへのルーティングの追加を行います。Aboutを追加した時と基本的な手順は同じです。
resource¥js¥router.jsファイルを開いてuserを追加します。User.vueファイルのimportも忘れずに行います。
import Router from 'vue-router'
import Home from './views/Home.vue'
import About from './views/About.vue'
import NotFound from './views/NotFound.vue'
import User from './views/User.vue'
export default new Router({
mode: 'history',
routes: [
{
path: '*',
component: NotFound
},
{
path: '/',
name: 'home',
component: Home
},
{
path: '/about',
name: 'about',
component: About
},
{
path: '/user',
name: 'user',
component: User
},
]
});
resources¥js¥viewsの下にUser.vueファイルを作成します。
<template>
<h1>ユーザ一覧</h1>
</template>
welcome.blade.phpファイルにrouter-linkを追加します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>Example</title>
<link rel="stylesheet" href="{{ mix('css/app.css') }}">
</head>
<body>
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link>
<router-link to="/about">About</router-link>
<router-link to="/user">ユーザ一覧</router-link>
</div>
<router-view/>
</div>
</div>
<script src="{{ mix('js/app.js') }}"></script>
</body>
</html>
ブラウザで確認するとユーザ一覧のリンクが追加されていることが確認できます。
ユーザ一覧をクリックするとUser.vueファイルの中身が表示されます。
ユーザデータ一括取得
axiosを使用してLaravelのAPIのエンドポイントにアクセスして、ユーザの一覧情報を取得します。まず、Laravel側でaxiosからアクセス可能なAPIエンドポイントの作成を行います。
Laravelではブラウザ経由のアクセスのルーティングはweb.phpファイルを利用しますが、API経由の場合のルーティングにはapi.phpファイルを利用します。web.phpを利用してもAPI経由のアクセスができないわけでなありません。
routesディレクトリの下にあるapi.phpファイルを開いてルーティングの設定を行います。
use Illuminate\Http\Request;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::get('/user',function (Request $request) {
$users = App\User::all();
return response()->json(['users' => $users]);
});
api.phpに記述したルーティングのURLは/api/userになります。axiosを設定する前にブラウザで/api/userに直接アクセスを行うと下記のようにusersテーブルの内容をJSONで確認することができます。
/api/userにブラウザからアクセスすることでusersデータが取得できることを確認したのでaxiosを使ってデータを取得します。コードはUser.vueファイルに記述します。v-forディレクティブを利用して取得したユーザデータを展開しています。
<template>
<div>
<h1>ユーザ一覧</h1>
<ul>
<li
v-for="user in users"
v-bind:key="user.id"
v-text="user.name"
></li>
</ul>
</div>
</template>
<script>
export default {
data(){
return{
users:[],
}
},
created(){
axios.get('/api/user')
.then(response => {
this.users = response.data.users;
})
.catch(error => {
console.log(error)
});
}
}
</script>
ブラウザで/userにアクセスするとユーザ名の一覧が表示されます。
ユーザデータの個別取得
先程はaxiosを利用してユーザデータを一括取得しましたが、今度はuserのidを利用して個別のデータを取得します。
router.jsファイルにユーザ詳細のページにアクセスするためのルーティングを追加します。:idを設定することで/user/1、/user/1000にアクセスした場合はすべて追加したルーティングへのアクセスになります。1や1000といった値はUserDetail.vueコンポーネント上では、this.$route.paramsを使って取得することができます。
import Router from 'vue-router'
// 中略
import UserDetail from './views/UserDetail.vue'
export default new Router({
mode: 'history',
routes: [
// 中略
{
path: '/user',
name: 'user',
component: User
},
{
path: '/user/:id',
name: 'user_detail',
component: UserDetail
},
]
});
UserDetail.vueファイルを作成します。$route.params.idには/user/:idで指定した:idの値が表示されます。
<template>
<div>
<h1>ユーザ詳細</h1>
<p>User Id: {{ $route.params.id }}</p>
</div>
</template>
各詳細情報へのアクセスはUser.vueファイルの各ユーザ行でリンクを設定します。
<template>
<div>
<h1>ユーザ一覧</h1>
<ul>
<li v-for="user in users" v-bind:key="user.id">
{{ user.name}} <router-link :to="`/user/${user.id}`">詳細</router-link>
</li>
</ul>
</div>
</template>
一番上のユーザ名の右に表示されている詳細ボタンをクリックするとidの1がブラウザ上に取得されます。他のユーザ名の左にある詳細ボタンをクリックすると異なるidがブラウザ上に表示されます。
axiosと受け取ったidを利用してユーザの個別情報をLaravelから取得します。
UserDetai.vueファイルをaxiosで取得した個別データを表示できるように変更を行います。
<template>
<div>
<div>
<h1>ユーザ詳細</h1>
<ul>
<li>User Id: {{ user.id }}</li>
<li>User Name: {{ user.name }}</li>
<li>User Email: {{ user.email }}</li>
</ul>
</div>
</div>
</template>
<script>
export default {
data(){
return {
id: this.$route.params.id,
user: ''
}
},
created(){
axios.get('/api/user/' + this.id)
.then(response => this.user = response.data.user)
.catch(erorr => console.log(error));
}
}
</script>
Laravel側のルーティングを追加するためにapi.phpを更新します。Laravelのモデルバインディングが利用されていおり、axiosではgetメソッドでidのみ記述していますがLaravelが内部で処理を行っているのでidを元に$userデータを取得してくれています。
Route::get('/user/{user}', function(App\User $user){
return response()->json(['user' => $user]);
});
ユーザ一覧の詳細ボタンをクリックするとユーザの詳細情報を確認することができます。下記はidが5のユーザ情報を表示させています。
ユーザ情報の更新
ユーザの詳細情報を取得することができたので次はユーザの情報を更新する更新ページの作成を行っていきます。
最初にrouter.jsにユーザ情報の更新を行うページへのルーティングの追加を行います。
import Router from 'vue-router'
//中略
import UserEdit from './views/UserEdit.vue'
export default new Router({
mode: 'history',
routes: [
//中略
{
path: '/user/:id/edit',
name: 'user_edit',
component: UserEdit
},
]
});
componentに指定しているUserEdit.vueファイルの作成を行います。ユーザ情報の更新を行うのでformタグまたv-modelディレクティブを使っています。更新ボタンをクリックするとupdateUserイベントが実行されます。
<template>
<div>
<div>
<h1>ユーザ更新</h1>
<p>User Id: {{ user.id }}</p>
<form @submit.prevent="updateUser">
<div class="form-group">
<label for="name">Name:</label>
<input v-model="user.name">
</div>
<div class="form-group">
<label for="email">Email:</label>
<input v-model="user.email">
</div>
<button type="submit">更新</button>
</form>
</div>
</div>
</template>
<script>
export default {
data(){
return {
id: this.$route.params.id,
user:{
id:'',
name: '',
email:''
}
}
},
methods:{
updateUser(){
axios.patch('/api/user/' + this.user.id,{
user: this.user
})
.then(response => {
this.user = response.data.user;
this.$router.push({ name: 'user_detail' ,params :{ id: this.$route.params.id }})
})
.catch(error => console.log(error));
},
},
created(){
axios.get('/api/user/' + this.id)
.then(response => this.user = response.data.user)
.catch(erorr => console.log(error));
}
}
</script>
axiosのpatchメソッドを使ってLaravelのAPIエンドポイントに変更データを送信しています。正常に変更が完了したあと、this.$router.pushメソッドを使ってnameに指定したuser_detailである詳細情報に移動する処理を行っています。
Laravel側のルーティングを追加します。追加したルーティングでユーザデータの更新を行っています。
Route::patch('/user/{user}', function(App\User $user,Request $request){
$user->update($request->user);
return response()->json(['user' => $user]);
});
User.vueファイルへは更新ページへのリンクを設定します。
<h1>ユーザ一覧</h1>
<ul>
<li
v-for="user in users"
v-bind:key="user.id"
>{{ user.name }}
<router-link :to="`/user/${user.id}`">詳細</router-link>
<router-link :to="`/user/${user.id}/edit`">更新</router-link>
</li>
</ul>
更新に関する設定がすべて完了したのでブラウザを使って動作確認を行います。
ユーザ一覧画面を表示して、上から3番目のAlessia Walshの更新ボタンをクリックします。
ユーザ更新画面が表示されます。
更新を行います。更新後は更新ボタンをクリックします。
更新ボタンを押すとユーザの詳細画面が表示されます。ユーザ情報が更新されていることがわかります。
再度一覧画面を確認すると3番目のユーザ名が変更したユーザになっていることが確認できます。
ユーザ情報の削除
ユーザの削除はユーザ一覧表に削除ボタンを追加して、ボタンをクリックするとその行のユーザ情報が削除できるように設定します。これまでの詳細、削除のようにVue Router側のルーティングの追加は必要ありません。
User.vueのhtmlのtemplateタグ部分を下記のように更新します。これまでCSSの設定は行っていませんでしたが、クリックがわかりやすいようにボタンにbtnのclassを設定しています。
削除ボタンを追加して、クリックイベントを設定しています。ボタンをクリックすると行の番号indexとuserのidがuserDeleteメソッドに渡されます。
<template>
<div>
<h1>ユーザ一覧</h1>
<ul>
<li v-for="(user,index) in users" v-bind:key="user.id" class="mb-1">
{{ user.name}}
<router-link class="btn btn-success" :to="`/user/${user.id}`">詳細</router-link>
<router-link class="btn btn-primary" :to="`/user/${user.id}/edit`">更新</router-link>
<span class="btn btn-danger" @click="userDelete(index, user.id)">削除</span>
</li>
</ul>
</div>
</template>
次にUser.vueのscriptタグ部分を更新します。
userDeleteメソッドを追加し、axiosのdeleteメソッドを使ってLaravelのAPIのエンドポイントに削除したユーザのidを送信します。送信後、正常に削除が行われたら、indexを使って削除ボタンを押したユーザ情報をブラウザ上から削除しています。
<script>
export default {
data(){
return{
users:[],
}
},
methods:{
userDelete(index, id){
axios.delete('/api/user/' + id)
.then(response => {
this.users.slice(id, 1)
})
.catch(error => console.log(error));
},
},
created(){
axios.get('/api/user')
.then(response=>{
this.users = response.data.users;
})
.catch(error => {
console.log(error)
});
}
}
</script>
Laravel側のルーティングファイルapi.phpにも削除に関するルーティングを追加します。
Route::delete('/user/{user}', function(App\User $user){
$user->delete();
return response()->json(['message' => 'delete successfully']);
});
ブラウザで削除の動作確認を行います。3番目のJoseph Legrosを削除します。
削除後のユーザ一覧は下記の通りです。
ページのリロードを行っても削除処理が行われていることを確認してください。
ユーザの作成処理
Laravelでユーザを作成する場合はユーザ登録画面が用意されているのでそこから行いますが今回はvue.js上からユーザの登録(作成)処理を行います。
作成のためのルーティングをroute.jsファイルに追加します。user/:idのルーティングの上に追加を行ってください。/user/:idの下に追加した場合は作成ボタンをクリックするとユーザの詳細画面が表示されます。
import Router from 'vue-router'
//中略
import UserCreate from './views/UserCreate.vue'
export default new Router({
mode: 'history',
routes: [
//中略
{
path: '/user',
name: 'user',
component: User
},
{
path: '/user/create',
name: 'user_create',
component: UserCreate
},
{
path: '/user/:id',
name: 'user_detail',
component: UserDetail
},
{
path: '/user/:id/edit',
name: 'user_edit',
component: UserEdit
},
]
});
UserCreate.vueファイルを作成します。
templateのタグ部分は下記の通りで、formタグとv-modelディレクティブを利用しています。作成ボタンをクリックするとcreateUserメソッドが実行されます。
<template>
<div>
<div>
<h1>ユーザ作成</h1>
<form @submit.prevent="createUser">
<div class="form-group">
<label for="name">Name:</label>
<input v-model="user.name">
</div>
<div class="form-group">
<label for="email">Email:</label>
<input v-model="user.email">
</div>
<div class="form-group">
<label for="password">Password:</label>
<input type="password" v-model="user.password">
</div>
<button type="submit">作成</button>
</form>
</div>
</div>
</template>
scriptタグ部分ではaxiosを使ってLaravelのAPIエンドポイントである/userにpostメソッドを使って入力した値を送信しています。ユーザが正常に作成できた後にpushメソッドを使ってユーザ一覧画面に移動します。
<script>
export default {
data(){
return {
user:{
name: '',
email:'',
password:''
}
}
},
methods:{
createUser(){
axios.post('/api/user',{
user: this.user
})
.then(response => {
this.user = response.data.user;
this.$router.push({ name: 'user'})
})
.catch(error => console.log(error));
},
}
}
</script>
Laravelのルーティングファイルapi.phpにユーザ作成の処理を追加します。
Route::post('/user', function(Request $request){
$user = App\User::create($request->user);
return response()->json(['user' => $user]);
});
User.vueファイルに作成ボタンを追加します。
<h1>ユーザ一覧</h1>
<router-link class="btn btn-primary" to="/user/create">作成</router-link>
ユーザの作成のための設定は完了したので、実際にユーザの作成をブラウザから行います。
ユーザ一覧画面に作成ボタンが表示されます。
作成ボタンをクリックすると入力フォームが表示されます。入力フォームにユーザ情報を入力します。
入力後、作成ボタンをクリックします。作成したユーザ情報が一覧の一番下に表示されているのを確認することができます。
まとめ
Laravelとvue.js、Vue Routerを利用して、/(ルート), /about, /userページの作成を行い、/userについてはページのリロードすることなく作成、更新、削除を行うことができました。