API

Laravel+Vue.js SPAのお勉強 Mac

 

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

 

 

Amazonおすすめ

iPad 9世代 2021年最新作

iPad 9世代出たから買い替え。安いぞ!🐱 初めてならiPad。Kindleを外で見るならiPad mini。ほとんどの人には通常のiPadをおすすめします><

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)