Help us understand the problem. What is going on with this article?

Laravel チュートリアルのレイアウトをVue.jsで置き換える

More than 1 year has passed since last update.

Laravel + Vue.js開発の勉強として
Laravelチュートリアル(基本のタスクリスト)のレイアウトをVue.jsで置き換えてみた作業記録

構成

  • Laravel:APIサーバー(DBのCRUD処理を提供)
  • Vue.js:フロントエンド処理一式

元ネタ

バージョン

  • Laravel 5.7
  • Vue.js 2.5.17

完成品

https://github.com/thanatos27/laravel-vue-quickstart

Laravel API作成

API仕様

Method URI Action Description
POST api/task App\Http\Controllers\TaskController@store 新規タスク作成
DELETE api/task{id} App\Http\Controllers\TaskController@destroy タスク削除
GET api/tasks App\Http\Controllers\TaskController@index タスク一覧取得

Taskテーブルの設定

terminal
php artisan make:migration create_tasks_table --create=tasks
database\migrations\xxxx_create_tasks_table.php
    public function up()
    {
        Schema::create('tasks', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->timestamps();
        });
    }

マイグレーション実行

terminal
php artisan migrate

Taskモデルを作成

terminal
php artisan make:model Task

ルーティング

routes\api.php
/**
 * Display All Tasks
 */
Route::get('tasks', 'TaskController@index');

/**
 * Add A New Task
 */
Route::post('task', 'TaskController@store');

/**
 * Delete An Existing Task
 */
Route::delete('task/{id}', 'TaskController@destroy');

Taskコントローラー作成

terminal
php artisan make:controller TaskController --resource
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Task;
use App\Http\Resources\TaskResource;

class TaskController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $tasks = Task::orderBy('created_at', 'asc')->get();

        return TaskResource::collection($tasks);
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $task = new Task;

        $task->name = $request->name;

        if($task->save()) {
            return new TaskResource($task);
        }
    } 

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        $task = Task::findOrFail($id);

        if ($task->delete()) {
            return new TaskResource($task);
        }
    }
}

リソース作成

terminal
php artisan make:resource TaskResource

レスポンスを送り返す時に、JSONへ変換する必要のある属性の配列を返す、
toArrayメソッドをリソースクラスで定義する。

app\Http\Resources\TaskResource.php
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
        ];
    }

Taskリストページ作成

ルーティング

routes\web.php
Route::get('/', function () {
    return view('tasks');
});

View

ポイントを抜粋して解説、
ファイル全体は以下を参照
https://github.com/thanatos27/laravel-vue-quickstart/blob/master/resources/views/tasks.blade.php

CSRF保護

resources\views\tasks.blade.php
        <!-- CSRF Protection -->
        <meta name="csrf-token" content="{{ csrf_token() }}">
        <script>window.Laravel = { csrfToken: '{{ csrf_token() }}' }</script>

Vueカスタム要素呼び出し部分

<navbar></navbar>:ナビゲーションバー
<tasks></tasks>:タスクリスト

resources\views\tasks.blade.php
        <div id="app">
            <navbar></navbar>
            <div class="container">
                <tasks></tasks>
            </div>
        </div>

フロントエンド(Vue.js)

quickstart-basicのテンプレートファイルをベースにVue.jsでリプレース
https://github.com/laravel/quickstart-basic/blob/master/resources/views/tasks.blade.php

コンポーネント登録

resources\js\app.js
Vue.component('navbar', require('./components/Navbar.vue'));
Vue.component('questionnaires', require('./components/Tasks.vue'));

ナビゲーションバー

resources\js\components\Navbar.vue
<template>
    <nav class="navbar navbar-default">
        <div class="container">
            <div class="navbar-header">

                <!-- Branding Image -->
                <a class="navbar-brand" href="/">
                    Task List
                </a>
            </div>
        </div>
    </nav>
</template>

タスクリスト

ポイントを抜粋して解説、
ファイル全体は以下を参照
https://github.com/thanatos27/laravel-vue-quickstart/blob/master/resources/js/components/Tasks.vue

表示/非表示

Laravelの@ifをVueのv-show構文で置き換え

resources/js/components/Tasks.vue
<!-- Current Tasks -->
<div v-show="tasks.length">
    <div class="panel panel-default">
        <div class="panel-heading">
            Current Tasks
        </div>

繰り返し制御

Laravelの@foreachをVueのv-for構文で置き換え

resources/js/components/Tasks.vue
<tr v-for="task in tasks" v-bind:key="task.id">
    <td class="table-text"><div>{{ task.name }}</div></td>

    <!-- Task Delete Button -->
    <td>
        <button @click="deleteTask(task.id)" class="btn btn-danger">
            <i class="fa fa-btn fa-trash"></i>Delete
        </button>
    </td>
</tr>

ボタンアクション

@clickで対応するmethodsを呼び出す

resources/js/components/Tasks.vue
<!-- Add Task Button -->
<div class="form-group">
  <div class="col-sm-offset-3 col-sm-6">
        <button @click="addTask()" class="btn btn-default">
            <i class="fa fa-btn fa-plus"></i>Add Task
        </button>
    </div>
</div>

methods

fetchAPIで各種Laravel APIにリクエストをする

fetchTasks

タスク一覧取得
URI:api/tasks
Method:GET

resources/js/components/Tasks.vue
fetchTasks() {
    fetch('api/tasks')
    .then(res => res.json())
    .then(res => {
        this.tasks = res.data;
    })
    .catch(err => console.log(err))
},

addTask

新規タスク追加
URI:api/task
Method:POST

resources/js/components/Tasks.vue
addTask() {
    this.errors = [];
    if(!this.task.name) {
        this.errors.push('Name required.');
        return;
    }

    fetch('api/task', {
        method: 'post',
        body: JSON.stringify(this.task),
        headers: {
            'content-type': 'application/json'
        }
    })
    .then(res => res.json())
    .then(data => {
        this.task.name = '';
        this.fetchTasks();
    })
    .catch(err => console.log(err))
},

deleteTask

タスク削除
URI:api/task/{id}
Method:`DELETE

resources/js/components/Tasks.vue
deleteTask(id) {
    fetch(`api/task/${id}`, {
        method: 'delete'
    })
    .then(res => res.json())
    .then(data => {
        this.fetchTasks();
    })
    .catch(err => console.log(err))
}

簡易的バリデーション処理

resources/js/components/Tasks.vue
addTask() {
    this.errors = [];
    if(!this.task.name) {
        this.errors.push('Name required.');
        return;
    }
resources/js/components/Tasks.vue
<!-- Display Validation Errors -->
<div v-show="errors.length" class="alert alert-danger">
    <strong>Whoops! Something went wrong!</strong>
    <br><br>

    <ul>
        <li v-for="error in errors" v-bind:key="error">{{ error }}</li>
    </ul>
</div>

以上

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした