LaravelでInertiaとBreezeを使ってVue3を導入・連携する方法

2756 回閲覧されました
みなさんこんにちは、jonioです。
Laravelのバージョン8にVue.jsのバージョン3を導入したかったのですがInertia(イナーシャ)を使えば導入する事ができるというのを知りました。
Inertiaを知らなかったので何ができる物なのかを調べたのですがInertiaが何かとVue.jsのバージョン3を導入する方法と設定しないといけない内容を解説します。
またLaravelのデータベースの情報をVue.jsに渡す方法を調べた結果axiosを使った方がいいというのを知ったのですがVueのバージョン3からcomposition apiというのが登場してバージョン2までのoptions apiとは書き方が別物になりaxiosでvueにデータベースの情報を渡す為のコードが少し変わります。
この記事を書いているのが2023年の5月ですがネットの情報はoptions apiで書いている物がほとんどで相当調べてやっとの思いで実装できたので次同じ事をしないといけなくなった時の自分と方法が分からなくて苦しんでいる人の為に情報を残します。
なおログイン機能にBreezeを使います。
目次 [隠す]
Inertiaとは
公式サイトはここから見る事ができるのですが↓の記載があります。
↑の赤枠の意味ですが「Inertiaはフレームワークではなくサーバーサイド・クライアントサイドのフレームワークに置き換わる物でもありません。むしろサーバーサイド・クライアントサイドが一緒に機能できる様にする物です。2つを繋ぐ接着剤と考えて下さい。現在クライアントサイドはReact・Vue・Svelteが対応していてサーバーサイドはLaravel・Railsが対応しています」
LaravelでVue.jsが使える物という事みたいです。
それではVue.jsのバージョン3を導入する方法を解説します。
Vue.jsを導入
Laravel8をインストールします。
composer create-project "laravel/laravel=8.*" プロジェクト名 |
次はBreezeをインストールしますが最新版をインストールすると不具合が起きるのでバージョンの指定をします。(今はこのバージョンが使えますがその内追いつかなくなって使えなくなるので注意して下さい)
composer require laravel/breeze:1.9.4 |
次はVue.jsのバージョン3をインストールします。
php artisan breeze:install vue |
そして↓のコマンドを叩きます。
npm install && npm run dev |
そしてLaravel Sail等でサーバーを立ち上げます。(「php artisan serve」でもいいと思います )
そしてトップページにアクセスして↓が表示されれば成功です。
Laravelだと↑のページはbladeですが今はVueに切り替わっています。
表示するためのファイルは「Laravelのプロジェクト > resources > js > Pages > Welcome.vue」です。
↓の赤枠はログイン・ユーザー登録です。
ログイン・ユーザー登録など認証関係のファイルは「Laravelのプロジェクト > resources > js > Pages > Auth」の下にあります。
ページ内容の変更
Welcom.vueもですが「〜.vue」(ページを表示するファイル)は変更したら「npm run dev」か「npm run watch」(ファイルの中身の変更を常に監視する)をしないと変更が表示されないので注意しましょう。
ルーティングの書き方
web.phpを↓にします。
<?php | |
use Illuminate\Foundation\Application; | |
use Illuminate\Support\Facades\Route; | |
use Inertia\Inertia; | |
/* | |
|-------------------------------------------------------------------------- | |
| Web Routes | |
|-------------------------------------------------------------------------- | |
| | |
| Here is where you can register web routes for your application. These | |
| routes are loaded by the RouteServiceProvider within a group which | |
| contains the "web" middleware group. Now create something great! | |
| | |
*/ | |
Route::get('/', function () { | |
return Inertia::render('Welcome', [ | |
'canLogin' => Route::has('login'), | |
'canRegister' => Route::has('register'), | |
'laravelVersion' => Application::VERSION, | |
'phpVersion' => PHP_VERSION, | |
]); | |
}); | |
Route::get('/dashboard', function () { | |
return Inertia::render('Dashboard'); | |
})->middleware(['auth', 'verified'])->name('dashboard'); | |
require __DIR__.'/auth.php'; | |
//トップページ | |
Route::get('/','PageController@index')->name('index'); //この行を追加 |
18行目〜25行目がトップページにアクセスした場合ですがInertiaを導入した場合は書き方が変わります。
34行目が追加したコードですがInertiaを使わない場合とルーティングの書き方は同じです。
コントローラーの書き方
コントローラーの作成方法は今までと同じです。
今回は「php artisan make:controller PageController」とします。
「PageController.php」のコードを↓にします。
<?php | |
namespace App\Http\Controllers; | |
use Illuminate\Http\Request; | |
use Inertia\Inertia; | |
class PageController extends Controller | |
{ | |
//ここから追加 | |
public function index() | |
{ | |
return Inertia::render('Index'); | |
} | |
//ここまで追加 | |
} |
15行目の「Index」が表示に使うファイル(Index.vue)で「Laravelのプロジェクト > resources > js > Pages」の下に配置します。
「Inertia::render( )」はInertiaを使ってvueのファイルを表示する為にあると思って下さい。
表示するVueファイル
Index.vueで表示する中身は何でもいいのですが↓とします。
<template> | |
<p>デモページ</p> | |
</template> |
簡素ですが「デモページ」と表示されます。
コンポーネントの使用
Index.vueの中に他のページと共通で使える部分(Header.vueとします)がある場合はコンポーネントにしますがその場合はコードを↓にします。
//ここから追加 | |
<script setup> | |
import Header from "../Components/Header"; | |
</script> | |
//ここまで追加 | |
<template> | |
<Header/> //この行を追加 | |
<p>デモページ</p> | |
</template> |
4行目のscriptタグの中に「setup」がありますがそんなもんと思いましょう。
5行目はHeader.vueを呼び出す為の記述で「Header」はHeader.vueのHeaderです。
11行目の「Header」もHeader.vueのHeaderです。
コンポーネントのファイルは「Laravelのプロジェクト > resources > js > Components」の下に配置します。
Header.vueで<template></template>の間に何かを記述すればそれをIndex.vueで表示するページで見る事ができます。
画像の使用
imgタグで画像を表示する時はコードを↓にします。
<img :src="'/images/header/logo.png'" alt=""> |
パスの起点がpublicになるのでpublicフォルダの下にimagesフォルダを作成してその下にheaderフォルダを作成してファイルを配置しました。
publicフォルダより下の階層に画像を置くならパスは私と同じでなくていいです。
scssの使用
ネットを調べると「nodesass」と「Dartsass」というのがありますがnodesassは非推奨(本当は2022年の10月辺りに廃止になるはずだったけど廃止にならなかった)なのでDartsassを入れましょう。
コマンドは「npm install -D sass-loader@^10 sass」ですがバージョンがその内追いつかなくなると思うので注意して下さい。
Index.vueでscssを使ってみますがコードを↓にします。
<script setup> | |
import Header from "../Components/Header"; | |
</script> | |
<template> | |
<Header/> | |
<p>デモページ</p> | |
</template> | |
//ここから追加 | |
<style lang="scss"> | |
//ここにscssを書く | |
</style> | |
//ここまで追加 |
12行目の様にstyleタグに「lang=”scss”」を付ければscssが使えます。
他のcssファイルの読み込み
webサイトを作るならリセットcssを使うはずです。
他のcssファイルを読み込む場合でもいいですがstyleタグの中でimportを使います。
Index.vueのコードを↓にします。
<script setup> | |
import Header from "../Components/Header"; | |
</script> | |
<template> | |
<Header/> | |
<p>デモページ</p> | |
</template> | |
<style lang="scss"> | |
@import '/css/reset.css'; //この行を追加 | |
</style> |
11行目を追加していますがパスはpublicが起点になってその下にデフォルトで存在しているcssフォルダがありその下にcssファイルを置いています。
グーグルフォントの使用
これもstyleタグでimportを使います。
<script setup> | |
import Header from "../Components/Header"; | |
</script> | |
<template> | |
<Header/> | |
<p>デモページ</p> | |
</template> | |
<style lang="scss"> | |
@import '/css/reset.css'; | |
@import url('https://fonts.googleapis.com/css?family=Noto+Sans+JP&display=swap'); //この行を追加 | |
</style> |
12行目を追加していますが「https」以降は以下のやり方で見つける事ができます。
グーグルフォントのサイトにアクセスします。
フォント名を入力します。
例えば「noto sans」と入力すると検索結果が表示されます。
一番左の「Noto Sans Japanese」を選択するとフォントのページに移動します。
下の方に行くとフォントの種類の選択になるのですが↓の赤枠を選択したとします。
そして↓の赤枠をクリックします。
すると↓になって赤枠の中の「href=” “」の” “の中身をコピーします。
そしてstyleタグの12行目の「https://fonts.googleapis.com/css?family=Noto+Sans+JP&display=swap」の部分にコピーしたコードを貼り付ければグーグルフォントが使えます。
これでLaravelの中でVue.jsを使う為の設定は大丈夫だと思います。
最後にLaravelでデータベースに登録した情報をVue.jsに渡します。
データベースに登録
まずはLaravelでデータベースに情報を登録する為の記述ですがこれは今回の説明の範囲外なのでコードだけ掲載します。
コードの内容は自分で理解して下さい。
テーブルの作成
postsテーブルを作成する為にモデルとマイグレーションファイルを作成します。
↓のコマンドでモデルとマイグレーションファイルを作成します。
php artisan make:model Post -m |
マイグレーションファイルに↓の記述をします。
<?php | |
use Illuminate\Database\Migrations\Migration; | |
use Illuminate\Database\Schema\Blueprint; | |
use Illuminate\Support\Facades\Schema; | |
class CreatePostsTable extends Migration | |
{ | |
/** | |
* Run the migrations. | |
* | |
* @return void | |
*/ | |
public function up() | |
{ | |
Schema::create('posts', function (Blueprint $table) { | |
$table->id(); | |
//ここから追加 | |
$table->string('title'); | |
$table->text('body'); | |
$table->string('permalink'); | |
$table->text('eyecatch'); | |
$table->string('youtuber'); | |
//ここまで追加 | |
$table->timestamps(); | |
}); | |
} | |
/** | |
* Reverse the migrations. | |
* | |
* @return void | |
*/ | |
public function down() | |
{ | |
Schema::dropIfExists('posts'); | |
} | |
} |
マイグレーションファイルの記述が終わったら「php artisan migrate」をします。
するとpostsテーブルにカラムが作成されます。
ルーティング
web.phpを↓にします。
<?php | |
use Illuminate\Foundation\Application; | |
use Illuminate\Support\Facades\Route; | |
use Inertia\Inertia; | |
/* | |
|-------------------------------------------------------------------------- | |
| Web Routes | |
|-------------------------------------------------------------------------- | |
| | |
| Here is where you can register web routes for your application. These | |
| routes are loaded by the RouteServiceProvider within a group which | |
| contains the "web" middleware group. Now create something great! | |
| | |
*/ | |
Route::get('/', function () { | |
return Inertia::render('Welcome', [ | |
'canLogin' => Route::has('login'), | |
'canRegister' => Route::has('register'), | |
'laravelVersion' => Application::VERSION, | |
'phpVersion' => PHP_VERSION, | |
]); | |
}); | |
Route::get('/dashboard', function () { | |
return Inertia::render('Dashboard'); | |
})->middleware(['auth', 'verified'])->name('dashboard'); | |
require __DIR__.'/auth.php'; | |
//トップページ | |
Route::get('/','PageController@index')->name('index'); | |
//記事の投稿 | |
Route::get('/create','PageController@create')->name('post.create'); | |
Route::post('/createStore','PageController@createStore')->name('createStore'); | |
//summernoteを使うページ | |
Route::get('/summernote/create','SummernoteController@create')->name('post.create'); | |
Route::post('/summernote/store','SummernoteController@store')->name('post.store'); |
記事の投稿に関する記述は37行目・38行目です。
今回登録内容の本文を作成する際にリッチエディタのsummernoteを使っていますが気になる人は↓の記事を読んで下さい。
コントローラー
PageController.phpを↓にします。
<?php | |
namespace App\Http\Controllers; | |
use Illuminate\Http\Request; | |
use Inertia\Inertia; | |
use App\Models\Post; | |
class PageController extends Controller | |
{ | |
public function index() | |
{ | |
return Inertia::render('Index'); | |
} | |
//ここから追加 | |
public function create() | |
{ | |
return view('post.create'); | |
} | |
public function createStore(Post $post,Request $request) | |
{ | |
$post->store($request); | |
return back()->with('message','記事の投稿が完了しました'); | |
} | |
//ここまで追加 | |
} |
またPost.phpを↓にします。
<?php | |
namespace App\Models; | |
use Illuminate\Database\Eloquent\Factories\HasFactory; | |
use Illuminate\Database\Eloquent\Model; | |
class Post extends Model | |
{ | |
use HasFactory; | |
//ここから追加 | |
protected $fillable = [ | |
'title', | |
'body', | |
'permalink', | |
'eyecatch', | |
'youtuber' | |
]; | |
public function store($request) | |
{ | |
$inputs = $request->validate([ | |
'title' => 'required', | |
'body' => 'required', | |
'permalink' => 'required', | |
'eyecatch' => 'required', | |
'youtuber' => 'required' | |
]); | |
$this->title = $inputs['title']; | |
$this->body = $inputs['body']; | |
$this->permalink = $inputs['permalink']; | |
$originalName = $request->file('eyecatch')->getClientOriginalName(); | |
$name = date('Yms_His').'_'.$originalName; | |
$request->file('eyecatch')->move('storage/eyecatch',$name); | |
$this->eyecatch = $name; | |
$this->youtuber = $inputs['youtuber']; | |
$this->save(); | |
} | |
//ここまで追加 | |
} |
ビュー
「Laravelのプロジェクト > resources > views」の下にpostフォルダを作成してその下にcreate.blade.phpを作成したらコードを↓にします。
<!DOCTYPE html> | |
<html lang="ja"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<link rel="stylesheet" href="{{ mix('css/reset.css') }}"> | |
<link rel="stylesheet" href="{{ mix('css/create.css') }}"> | |
<script src="https://kit.fontawesome.com/xxxxxxxxxxxxx.js" crossorigin="anonymous"></script> | |
<script src="https://code.jquery.com/jquery-3.5.1.min.js" crossorigin="anonymous"></script> | |
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script> | |
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous"> | |
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script> | |
<link href="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-bs4.min.css" rel="stylesheet"> | |
<script src="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-bs4.min.js"></script> | |
<title>記事の作成</title> | |
</head> | |
<body> | |
<header class="header"> | |
<a href="/"><i class="fas fa-home"></i><span>トップページへ</span></a> | |
<a href="">記事の作成</a> | |
<a href="">おすすめ動画の作成</a> | |
</header> | |
<main class="main"> | |
@if($errors->any()) | |
<ul class="error"> | |
@foreach($errors->all() as $error) | |
<li>{{$error}}</li> | |
@endforeach | |
</ul> | |
@endif | |
<h2 class="new-post-add">新規投稿を追加</h2> | |
<form action="{{route('createStore')}}" method="post" enctype="multipart/form-data"> | |
@csrf | |
<div class="main-side-wrap"> | |
<div class="main-area"> | |
<input class="title-add" name="title" placeholder="タイトルを追加" value="{{old('title')}}"> | |
<p class="url-add">パーマリンク : https://xxxxxx.com/<input type="text" name="permalink" placeholder="パーマリンクを追加" value="{{old('permalink')}}"></p> | |
<div class="summernote-container"> | |
<textarea id="summernote" name="body">{{old('body')}}</textarea> | |
</div> | |
</div> | |
<div class="side-area"> | |
<div class="release-container"> | |
<h2>公開</h2> | |
<input type="submit" value="記事を公開する"> | |
</div> | |
<div class="eyecatch-image-container"> | |
<h2>アイキャッチ画像</h2> | |
<div class="wrap"> | |
<input type="file" name="eyecatch" accept="image/jpg,img/png"> | |
<p>アイキャッチ画像を追加</p> | |
</div> | |
</div> | |
<div class="youtuber-container"> | |
<h2>YouTuber名の入力</h2> | |
<input type="text" name="youtuber" placeholder="HIKAKIN" value="{{old('youtuber')}}"> | |
</div> | |
</div> | |
</div> | |
</div> | |
</form> | |
</main> | |
</body> | |
</html> | |
<script> | |
$('#summernote').summernote({ | |
placeholder: 'ここにテキストを書きます。画像も入れる事ができます。', | |
height: 500, | |
}); | |
</script> |
この時のcreate.scssとreset.scssは↓です。
.header{ | |
background-color:#4DA8F5; | |
display: flex; | |
align-items:center; | |
column-gap:5%; | |
padding: 10px 6%; | |
@media screen and (min-width:768px){ | |
column-gap:3%; | |
} | |
.home-icon{ | |
width: 27px; | |
height:auto; | |
} | |
a{ | |
color:#fff; | |
text-decoration:none; | |
font-size: 13px; | |
@media screen and (min-width:768px){ | |
font-size: 16px; | |
} | |
.fa-home{ | |
color:#000; | |
display: inline-block; | |
margin-right: 10px; | |
} | |
span{ | |
padding-bottom: 10px; | |
} | |
} | |
} | |
.main{ | |
background-color:#F0F0F1; | |
padding: 20px 6%; | |
min-height:100vh; | |
.main-side-wrap{ | |
display: flex; | |
flex-direction: column; | |
align-items: flex-start; | |
margin-top: 20px; | |
@media screen and (min-width:768px){ | |
flex-direction: row; | |
column-gap: 40px; | |
} | |
.title-add{ | |
color:#646970; | |
height: 30px; | |
font-size: 24px; | |
font-weight: normal; | |
@media screen and (min-width:768px){ | |
width: 100%; | |
} | |
} | |
.url-add{ | |
margin-top: 20px; | |
input{ | |
display: inline-block; | |
margin-top: 10px; | |
color:#646970; | |
border:1px solid #8C8F94; | |
width: 280px; | |
height: 20px; | |
@media screen and (min-width:768px){ | |
margin-left: 5px; | |
margin-top: 0; | |
} | |
} | |
} | |
.main-area{ | |
width: 100%; | |
@media screen and (min-width:768px){ | |
width: 80%; | |
} | |
} | |
.side-area{ | |
width: 100%; | |
@media screen and (min-width:768px){ | |
width: 20%; | |
} | |
.release-container{ | |
background-color:#fff; | |
border:1px solid #707070; | |
h2{ | |
padding: 15px; | |
border-bottom:1px solid #707070; | |
font-weight: bold; | |
} | |
input{ | |
color:#fff; | |
background-color:#4DA8F5; | |
border-radius:5px; | |
padding: 5px 13px; | |
border:none; | |
display: inline-block; | |
margin-top: 15px; | |
margin-left: 13px; | |
margin-bottom: 15px; | |
} | |
} | |
.eyecatch-image-container{ | |
margin-top: 35px; | |
background-color:#fff; | |
border:1px solid #707070; | |
h2{ | |
padding: 15px; | |
border-bottom:1px solid #707070; | |
font-weight: bold; | |
} | |
.wrap{ | |
padding-top: 15px; | |
padding-bottom: 33px; | |
position:relative; | |
input{ | |
color:#646970; | |
font-size: 13px; | |
border:none; | |
display: inline-block; | |
margin-top: 15px; | |
margin-left: 13px; | |
margin-bottom: 15px; | |
position: absolute; | |
top: 15px; | |
z-index: 2; | |
opacity:0; | |
} | |
p{ | |
text-decoration: underline; | |
cursor: pointer; | |
position: absolute; | |
top: 15px; | |
left: 10px; | |
color:#646970; | |
} | |
} | |
} | |
.youtuber-container{ | |
margin-top: 35px; | |
background-color:#fff; | |
border:1px solid #707070; | |
h2{ | |
padding: 15px; | |
border-bottom:1px solid #707070; | |
font-weight: bold; | |
} | |
input{ | |
color:#646970; | |
font-size: 13px; | |
padding: 5px 13px; | |
border:1px solid #8C8F94; | |
display: inline-block; | |
margin-top: 15px; | |
margin-left: 13px; | |
margin-bottom: 13px; | |
border-radius:5px; | |
width: 80%; | |
} | |
} | |
} | |
} | |
.new-post-add{ | |
font-size: 24px; | |
font-weight: normal; | |
} | |
.summernote-container{ | |
margin-top: 35px; | |
} | |
} |
/* | |
html5doctor.com Reset Stylesheet | |
v1.6.1 | |
Last Updated: 2010-09-17 | |
Author: Richard Clark - http://richclarkdesign.com | |
Twitter: @rich_clark | |
*/ | |
html, body, div, span, object, iframe, | |
h1, h2, h3, h4, h5, h6, p, blockquote, pre, | |
abbr, address, cite, code, | |
del, dfn, em, img, ins, kbd, q, samp, | |
small, strong, sub, sup, var, | |
b, i, | |
dl, dt, dd, ol, ul, li, | |
fieldset, form, label, legend, | |
table, caption, tbody, tfoot, thead, tr, th, td, | |
article, aside, canvas, details, figcaption, figure, | |
footer, header, hgroup, menu, nav, section, summary, | |
time, mark, audio, video { | |
margin:0; | |
padding:0; | |
border:0; | |
outline:0; | |
font-size:100%!important; | |
vertical-align:baseline; | |
background:transparent; | |
} | |
body { | |
line-height:1; | |
} | |
article,aside,details,figcaption,figure, | |
footer,header,hgroup,menu,nav,section { | |
display:block; | |
} | |
nav ul { | |
list-style:none; | |
} | |
blockquote, q { | |
quotes:none; | |
} | |
blockquote:before, blockquote:after, | |
q:before, q:after { | |
content:''; | |
content:none; | |
} | |
a { | |
margin:0; | |
padding:0; | |
font-size:100%; | |
vertical-align:baseline; | |
background:transparent; | |
} | |
/* change colours to suit your needs */ | |
ins { | |
background-color:#ff9; | |
color:#000; | |
text-decoration:none; | |
} | |
/* change colours to suit your needs */ | |
mark { | |
background-color:#ff9; | |
color:#000; | |
font-style:italic; | |
font-weight:bold; | |
} | |
del { | |
text-decoration: line-through; | |
} | |
abbr[title], dfn[title] { | |
border-bottom:1px dotted; | |
cursor:help; | |
} | |
table { | |
border-collapse:collapse; | |
border-spacing:0; | |
} | |
/* change border colour to suit your needs */ | |
hr { | |
display:block; | |
height:1px; | |
border:0; | |
border-top:1px solid #cccccc; | |
margin:1em 0; | |
padding:0; | |
} | |
input, select { | |
vertical-align:middle; | |
} | |
p,.nav{ | |
margin:0; | |
} | |
h2{ | |
margin-bottom: 0!important; | |
} |
またwebpack.mix.jsは↓です。
const mix = require('laravel-mix'); | |
/* | |
|-------------------------------------------------------------------------- | |
| Mix Asset Management | |
|-------------------------------------------------------------------------- | |
| | |
| Mix provides a clean, fluent API for defining some Webpack build steps | |
| for your Laravel applications. By default, we are compiling the CSS | |
| file for the application as well as bundling up all the JS files. | |
| | |
*/ | |
mix.js('resources/js/app.js', 'public/js') | |
.vue() | |
.postCss('resources/css/app.css', 'public/css', [require('tailwindcss'), require('autoprefixer')]) | |
.sass('resources/sass/reset.scss', 'public/css/reset.css') | |
.sass('resources/sass/create.scss', 'public/css/create.css') | |
.alias({ | |
'@': 'resources/js', | |
}); | |
if (mix.inProduction()) { | |
mix.version(); | |
} |
npm run devをするとビューの見た目が↓になります。
入力内容を入力して「記事を公開する」をクリックすると入力した内容がデータベースに保存されます。
Vueにデータベースの情報を渡す
それではVueにデータベースの情報を渡します。
api.php
ルーティングの設定をする時はweb.phpでしたがaxiosを使う時はapi.phpを使います。
web.phpと同じ階層にあります。
api.phpのコードを↓にします。
<?php | |
use Illuminate\Http\Request; | |
use Illuminate\Support\Facades\Route; | |
/* | |
|-------------------------------------------------------------------------- | |
| 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::middleware('auth:sanctum')->get('/user', function (Request $request) { | |
return $request->user(); | |
}); | |
Route::resource('/post','PostController'); //この行を追加 |
次は コントローラーです。
コントローラー
apiを使う時のコントローラーを作成しますがコマンドが「php artisan make:controller コントローラー名 –api」です。
今回はPostControllerを作成するので↓のコマンドを叩きます。
php artisan make:controller PostController --api |
api用のコントローラーも通常のコントローラーと同じ階層に作成されます。
リソースコントローラーの時と同じ様にルートが勝手に設定されますので「php artisan route:list」で確認して下さい。
PostController.phpに↓の記述をします。
<?php | |
namespace App\Http\Controllers; | |
use Illuminate\Http\Request; | |
use App\Models\Post; //この行を追加 | |
class PostController extends Controller | |
{ | |
/** | |
* Display a listing of the resource. | |
* | |
* @return \Illuminate\Http\Response | |
*/ | |
public function index() | |
{ | |
//ここから追加 | |
$posts = Post::all(); | |
return $posts; | |
//ここまで追加 | |
} | |
/** | |
* Store a newly created resource in storage. | |
* | |
* @param \Illuminate\Http\Request $request | |
* @return \Illuminate\Http\Response | |
*/ | |
public function store(Request $request) | |
{ | |
// | |
} | |
/** | |
* Display the specified resource. | |
* | |
* @param int $id | |
* @return \Illuminate\Http\Response | |
*/ | |
public function show($id) | |
{ | |
// | |
} | |
/** | |
* Update the specified resource in storage. | |
* | |
* @param \Illuminate\Http\Request $request | |
* @param int $id | |
* @return \Illuminate\Http\Response | |
*/ | |
public function update(Request $request, $id) | |
{ | |
// | |
} | |
/** | |
* Remove the specified resource from storage. | |
* | |
* @param int $id | |
* @return \Illuminate\Http\Response | |
*/ | |
public function destroy($id) | |
{ | |
// | |
} | |
} |
これでデータベースの情報をVueに渡す事ができる様になったので次はVueですがIndex.vueを使います。
Index.vue
Index.vueのコードを↓にします。
<script setup> | |
import Header from "../Components/Header"; | |
//ここから追加 | |
import { ref } from "vue"; | |
let posts = ref([]); | |
axios.get("/api/post").then(response => {posts.value = response.data}); | |
console.log(posts); | |
//ここまで追加 | |
</script> | |
<template> | |
<p>デモページ</p> | |
//ここから追加 | |
<ul> | |
<li | |
v-for="post in posts" | |
:key="post.id" | |
>{{ post.title }}</li> | |
</ul> | |
//ここまで追加 | |
</template> | |
<style lang="scss"> | |
@import '/css/reset.css'; | |
@import url('https://fonts.googleapis.com/css?family=Noto+Sans+JP&display=swap'); | |
</style> |
8行目のrefに関してざっくりとした説明をします。
例えばJavaScriptで↓のコードを考えます。
let display = "aaaaa"; | |
display = "bbbbb"; | |
display = "ccccc"; | |
console.log(display); |
displayが何になっているかをデベロッパーツールで確認すると「ccccc」と表示されます。
Vue3の場合はこれをする為に8行目の「ref([ ]);」のref( )が必要になります。
カッコの中は最初の値を書きます(JavaScriptの例のaaaaa)が[ ]になるのはLaravelからVueに渡された情報が配列になるからです。
配列になっているのを確認する為に10行目の「console.log(posts);」があります。
デベロッパーツールで確認します。
この配列の内容を表示する為に22行目〜25行目のv-forディレクティブがあり、「{{post.title}}」でデータベースに存在するtitleカラムの内容が表示されます。
v-forディレクティブを知らない方は↓を読んで下さい。
これで完成です。