SPA環境のお勉強ってことで
https://qiita.com/minato-naka/items/9241d9c7a7433985056d
これ見ながらぼちぼちやってく🐱
https://github.com/yuukanehiro/Laravel-Vue.js-SPA-Study
もくじ
環境構築
docker │ ┝nginx │ ┗Dockerfile │ ┝php │ ┝php.ini │ ┗Dockerfile │ docker-compose.yml
./docker-compose.yml
version: '3'
services:
php:
container_name: php
build: ./docker/php
volumes:
- ./src:/var/www
links:
- db
nginx:
image: nginx
container_name: nginx
ports:
- 80:80
volumes:
- ./src:/var/www
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php
db:
image: mysql:5.7
container_name: db
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: laravel
MYSQL_USER: docker
MYSQL_PASSWORD: docker
TZ: 'Asia/Tokyo'
command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
volumes:
- ./docker/db/data:/var/lib/mysql
- ./docker/db/my.cnf:/etc/mysql/conf.d/my.cnf
- ./docker/db/sql:/docker-entrypoint-initdb.d
ports:
- 3306:3306
./docker/nginx/default.conf
server {
listen 80;
index index.php index.html;
root /var/www/public;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
./docker/php/php.ini
[Date] date.timezone = "Asia/Tokyo" [mbstring] mbstring.internal_encoding = "UTF-8" mbstring.language = "Japanese"
./docker/php/Dockerfile
FROM php:7.2-fpm COPY php.ini /usr/local/etc/php/ RUN apt-get update \ && apt-get install -y zlib1g-dev mariadb-client \ && docker-php-ext-install zip pdo_mysql #Composer install COPY --from=composer /usr/bin/composer /usr/bin/composer ENV COMPOSER_ALLOW_SUPERUSER 1 ENV COMPOSER_HOME /composer ENV PATH $PATH:/composer/vendor/bin WORKDIR /var/www RUN composer global require "laravel/installer"
Laravelインストール
Laravel-Vue.js-SPA-Study $ composer global require laravel/installer ravel-Vue.js-SPA-Study $ composer create-project --prefer-dist laravel/laravel src
起動させる
Laravel-Vue.js-SPA-Study $ docker-compose up -d
project docker │ ┝nginx │ ┝default.conf │ ┗Dockerfile │ ┝php │ ┝php.ini │ ┗Dockerfile │ docker-compose.yml │ src
起動確認

http://localhost/
MySQL接続確認
$ docker exec -it db-host bash root@e3e8d37b8b70:/# mysql -u root -p Enter password: 「root」と入力 Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 5 Server version: 5.7.32 MySQL Community Server (GPL) Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
laravel/uiインストール
src $ composer require laravel/ui src $ npm install && npm run dev
雛形をつくる
src $ php artisan ui vue
Vue Routerインストール
src $ npm install --save vue-router
ビルド
src $ npm run dev
/.gitignore
docker/db/data vendor
src/app/.ignore
/node_modules /public/hot /public/storage + /public/js + /public/css /storage/*.key /vendor .env .env.backup .phpunit.result.cache Homestead.json Homestead.yaml npm-debug.log yarn-error.log
js, cssフォルダを追記する
npm run devをするのが面倒くさい時は
src $ npm run watch
routes/web.php
// Route::get('/', function () {
// return view('welcome');
// });
Route::get('/{any}', function () {
return view('app');
})->where('any', '.*');
resources/views/app.brade.php
<!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">
</div>
<!-- Scripts -->
<script src="{{ mix('/js/app.js') }}" defer></script>
</body>
</html>
<div id="app"> + <example-component></example-component> </div>
追加する

http://localhost/
resources/js/compoonents/HeaderComponent.vue
<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/views/app.brade.php
・・・ <div id="app"> <header-component></header-component> + <example-component></example-component> </div> ・・・
resources/js/compoonents/TaskListComponent.vue
<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>
resources/js/app.js
+ import VueRouter from 'vue-router';
import HeaderComponent from "./components/HeaderComponent";
+ import TaskListComponent from "./components/TaskListComponent";
window.Vue = require('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
});
ここが重要
routes: [
{
path: '/tasks',
name: 'task.list',
component: TaskListComponent
},
]
- パス:/tasks
- 名前:task.list
- コンポーネント: TaskListComponent
resources/views/app.brade.php
・・・ <div id="app"> <header-component></header-component> <example-component></example-component> + <router-view></router-view> </div> ・・・
resources/js/compoonents/HeaderComponent.vue
<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>
+ <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>
</nav>
</div>
</div>
</template>
<script>
export default {}
</script>
ボタンにリンクを追加する

http://localhost/tasks
タスク詳細コンポーネント
resources/js/compoonents/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>
+ export default {
+ props: {
+ taskId: String
+ }
+ }
taskIdで受け取る値を定義
ここでバインドしている
<input type="text" class="col-sm-9 form-control-plaintext" readonly id="id"
v-bind:value="taskId">
resources/js/app.js
import VueRouter from 'vue-router';
import HeaderComponent from "./components/HeaderComponent";
import TaskListComponent from "./components/TaskListComponent";
+ import TaskShowComponent from "./components/TaskShowComponent";
・・・
const router = new VueRouter({
mode: 'history',
routes: [
{
path: '/tasks',
name: 'task.list',
component: TaskListComponent
},
+ {
+ path: '/tasks/:taskId',
+ name: 'task.show',
+ component: TaskShowComponent,
+ props: true
+ },
]
});
resources/js/compoonents/TaskListComponent.vue
+ <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>

http://localhost/tasks/1
反映されなかったらcommand + Rで。
タスク登録コンポーネント
resources/js/components/TaskCreateComponent.vue
<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>
resources/js/app.js
import VueRouter from 'vue-router';
import HeaderComponent from "./components/HeaderComponent";
import TaskListComponent from "./components/TaskListComponent";
import TaskShowComponent from "./components/TaskShowComponent";
+ import TaskCreateComponent from "./components/TaskCreateComponent";
・・・
const router = new VueRouter({
mode: 'history',
routes: [
{
path: '/tasks',
name: 'task.list',
component: TaskListComponent
},
{
path: '/tasks/:taskId',
name: 'task.show',
component: TaskShowComponent,
props: true
},
+ {
+ path: '/tasks/create',
+ name: 'task.create',
+ component: TaskCreateComponent
+ },
]
});
resources/js/compoonents/HeaderComponent.vue
+ <router-link v-bind:to="{name: 'task.create'}">
<button class="btn btn-success">ADD</button>
+ </router-link>

http://localhost/tasks/create
タスク編集コンポーネンット
resources/js/components/TaskEditComponent.vue
<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>
resources/js/app.js
import VueRouter from 'vue-router';
import HeaderComponent from "./components/HeaderComponent";
import TaskListComponent from "./components/TaskListComponent";
import TaskShowComponent from "./components/TaskShowComponent";
import TaskCreateComponent from "./components/TaskCreateComponent";
+ import TaskEditComponent from "./components/TaskEditComponent";
・・・
const router = new VueRouter({
mode: 'history',
routes: [
{
path: '/tasks',
name: 'task.list',
component: TaskListComponent
},
{
path: '/tasks/:taskId',
name: 'task.show',
component: TaskShowComponent,
props: true
},
{
path: '/tasks/create',
name: 'task.create',
component: TaskCreateComponent
},
+ {
+ path: '/tasks/:taskId/edit',
+ name: 'task.edit',
+ component: TaskEditComponent,
+ props: true
+ },
]
});
<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>
<router-link v-bind:to="{name: 'task.show', params: {taskId: 1}}">
<button class="btn btn-primary">Show</button>
</router-link>
</td>
<td>
+ <router-link v-bind:to="{name: 'task.edit', params: {taskId: 1}}">
<button class="btn btn-success">Edit</button>
+ </router-link>
</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>
<router-link v-bind:to="{name: 'task.show', params: {taskId: 2}}">
<button class="btn btn-primary">Show</button>
</router-link>
</td>
<td>
+ <router-link v-bind:to="{name: 'task.edit', params: {taskId: 2}}">
<button class="btn btn-success">Edit</button>
+ </router-link>
</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>
<router-link v-bind:to="{name: 'task.show', params: {taskId: 3}}">
<button class="btn btn-primary">Show</button>
</router-link>
</td>
<td>
+ <router-link v-bind:to="{name: 'task.edit', params: {taskId: 3}}">
<button class="btn btn-success">Edit</button>
+ </router-link>
</td>
<td>
<button class="btn btn-danger">Delete</button>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {}
</script>

http://localhost/tasks/1/edit






