LaravelとVue.jsで自作のプロダクトを制作しています。
そこでVue.jsで表示する内容にLaravelのModelを表示させたSPAを作成したいと思います。
※制作途中のプロダクトで行ったので、Model・Controllerは事前に作成してあるものを使用いたしますので説明を省くところが多いです。ご了承下さい。
使用する主なソフトのバージョンは以下の通りです。
Laravel: 5.7
Vue.js: 2.5.17
node: 6.7.0
axios: 0.18
vue-router: 3.0.2
LaravelとVue.jsの準備
Laravel
ドットインストールで一通りの概要を理解し、
動画の内容を参考にして環境を準備しました。
プレミアム会員でしか動画を視聴できないのでご了承ください。
Vue.js
以下の記事を一通り行い、インストールしました。
わかりやすく、大変参考になりました。
LaravelからVue.jsを使う最短レシピ
https://qiita.com/fruitriin/items/e0f2c9aa035c3ff2c874
axiosとvue-routerの準備
axiosによるHTTPリクエストで、登録されているModelのデータをajaxでjsonに変換して取得します。
また、vue-routerを使用することでSPA環境を作成することができます。
vue-routerをインストール
package.jsonにインストールするvue-routerを記載します。
axiosはLaravelをインストールするとすでにパッケージがありますので、
package.jsonに記載されているならインストールの必要なしです。
{
"private": true,
"scripts": {
"dev": "npm run development",
"development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
"watch": "npm run development -- --watch",
"watch-poll": "npm run watch -- --watch-poll",
"hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
"prod": "npm run production",
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
},
"devDependencies": {
"axios": "^0.18",
"bootstrap": "^4.0.0",
"cross-env": "^5.1",
"jquery": "^3.2",
"laravel-mix": "^4.0.15",
"lodash": "^4.17.5",
"popper.js": "^1.12",
"resolve-url-loader": "^2.3.1",
"sass": "^1.15.2",
"sass-loader": "^7.1.0",
"vue": "^2.5.17",
"vue-template-compiler": "^2.6.8"
},
"dependencies": {
"vue-router": "^3.0.2" // 追加
}
}
端末でvue-routerをインストールします。
$ npm install vue-router
vue-routerでSPAを作成
ルーティング設定
以下の通り3つそれぞれにshow.blade.phpにアクセスできるようルーティングを設定します。
なぜかわかりませんが、stadiumを一番下にしないとshow.blade.phpにアクセスした時、自動的にstadiumのリンクを選択したままになりませんでした。
Route::get('/stadium/{id}/address', 'StadiumPostsController@show')->where('id', '[0-9]+');
Route::get('/stadium/{id}/lat_lon', 'StadiumPostsController@show')->where('id', '[0-9]+');
Route::get('/stadium/{id}/stadium', 'StadiumPostsController@show')->where('id', '[0-9]+');
コントローラ設定
Modelの内容を取得してViewの方にデータを表示させる処理を記述します。
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\StadiumPost;
class StadiumPostsController extends Controller
{
public function show($id) {
$post = StadiumPost::findOrFail($id);
return view('show')->with('stadium_post', $post);
}
}
リンク元のビューを作成
ブレードにrouter-linkの記述を作成します。
最終的には3つそれぞれ、「スタジアムの名前」「スタジアムのある位置情報」「スタジアムの住所」を Modelから取得できる様にします。
router-viewには最終的にModelの内容を表示できる様にします。
<!DOCTYPE html>
<html lang="{{ app()->getLocale() }}">
<head>
<meta charset="utf-8">
<meta name="csrf-token" content="{{ csrf_token() }}">
<link rel="stylesheet" href="{{ mix('/css/app.css') }}">
<link rel="stylesheet" href="/css/styles.css">
</head>
<body>
<div class="container">
<div id="app">
<nav>
<ul>
<router-link :to="{ name: 'stadium' }" exact>stadium</router-link>
<router-link :to="{ name: 'lat_lon' }">lat_lon</router-link>
<router-link :to="{ name: 'address' }">address</router-link>
</ul>
</nav>
<router-view></router-view>
</div>
<!-- 作成途中のソースコード -->
</body>
<script src="{{ mix('js/app.js') }}"></script>
</html>
Vue.jsでvue-routerを使ったルーティング作成
リンク元にあった同じnameから相当のコンポーネントにあるテンプレートに推移します。
pathもルーティング設定と同じ様に設定します。
require('./bootstrap');
window.Vue = require('vue');
import VueRouter from 'vue-router';
import Stadium from './components/StadiumComponent.vue';
import Lat_lon from './components/Lat_lonComponent.vue';
import Address from './components/AddressComponent.vue';
Vue.use(VueRouter)
const routes = [
{ path: '/stadium/:id/stadium', name: 'stadium', component: Stadium},
{ path: '/stadium/:id/lat_lon', name: 'lat_lon', component: Lat_lon },
{ path: '/stadium/:id/address', name: 'address', component: Address },
];
const router = new VueRouter({
mode: 'history',
routes
});
const app = new Vue({
router
}).$mount('#app');
テンプレート内容の作成
.vue
ファイルによってリンク元にあるrouter-view内にデータを表示します。
<template>
<div class="col-md-8 col-md-offset-2">
Stadium
</div>
</template>
<template>
<div class="col-md-8 col-md-offset-2">
Lat_lon
</div>
</template>
<template>
<div class="col-md-8 col-md-offset-2">
Address
</div>
</template>
CSS
リンクをクリックした時に文字を赤くします。わかりやすくするため実装しました。
.router-link-active {
color: rgb(255, 0, 0);
}
ここまでのLaravel+Vue.js+vue-router
URLから/stadium/:id/stadium
にアクセスします。
以下の通り、リンクをクリックするとテンプレートの内容が表示されます。
Modelをjsonに変換する
端末上よりModelをjson形式に変換するルーティングとコントローラを作成します。
Route::get('/stadium/{id}/address', 'StadiumPostsController@show')->where('id', '[0-9]+');
Route::get('/stadium/{id}/lat_lon', 'StadiumPostsController@show')->where('id', '[0-9]+');
Route::get('/stadium/{id}/stadium', 'StadiumPostsController@show')->where('id', '[0-9]+');
Route::get('ajax/stadium', 'Ajax\StadiumController@index');
$ php artisan make:controller Ajax\\StadiumController
コントローラには使用するModelであるStadiumPostを使うようにします。
このコントローラにアクセスすることで自動的にjson形式にしてくれます。
<?php
namespace App\Http\Controllers\Ajax;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class StadiumController extends Controller
{
public function index() {
return \App\StadiumPost::all();
}
}
axiosを使ったModel内容表示するSPA作成
.vue
ファイルのテンプレートにv-forでModelのリストを表示します。
scriptにはaxiosによるHTTPリクエストでjson形式Modelデータのレスポンスを返します。
また、axiosは非同期処理を行い呼び出し元のビューに戻るので一度関数としては終了します。
<template>
<div class="col-md-8 col-md-offset-2">
<li v-for="std in stadium">
<span>{{ std.stadium }}</span>
</li>
</div>
</template>
<script>
export default {
data() {
return {
stadium: {}
}
},
mounted() {
var self = this;
var url = '/ajax/stadium';
axios.get(url).then(function(response){
self.stadium = response.data;
});
}
}
</script>
<template>
<div class="col-md-8 col-md-offset-2">
<li v-for="std in stadium">
<span>{{ std.latitude }} , {{ std.longitude }}</span>
</li>
</div>
</template>
<script>
export default {
data() {
return {
stadium: {}
}
},
mounted() {
var self = this;
var url = '/ajax/stadium';
axios.get(url).then(function(response){
self.stadium = response.data;
});
}
}
</script>
<template>
<div class="col-md-8 col-md-offset-2">
<li v-for="std in stadium">
<span>{{ std.address }}</span>
</li>
</div>
</template>
<script>
export default {
data() {
return {
stadium: {}
}
},
mounted() {
var self = this;
var url = '/ajax/stadium';
axios.get(url).then(function(response){
self.stadium = response.data;
});
}
}
</script>
Laravel+Vue.js+vue-router+axiosによるModelデータ出力
以下の通り「スタジアムの名前」「スタジアムのある位置情報」「スタジアムの住所」を Modelから取得できるようになりました。
参考
Laravelとvueの連携!データベース内の一覧を表示する方法
Laravel5.6とVue.jsで簡単なシングルページアプリケーション
【書籍】Vue.js入門 基礎から実践アプリケーション開発まで