ru:https://highload.today/blogs/spa-laravel-i-vue-za-45-minut/ ua:https://highload.today/uk/blogs/spa-laravel-i-vue-za-45-minut/
logo
Веб-разработка      02/12/2021

Как написать одностраничное приложение на Laravel и Vue.js за 45 минут

Сергей Гришечкин BLOG

Backend Developer во FlexMade

Всем привет! В этой статье я предлагаю вам написать вместе со мной простое одностраничное приложение меньше, чем за час. Для этого воспользуемся веб-фреймворком Laravel, который по умолчанию включает в себя популярный фронтенд-фреймворк Vue.js.

composer create-project — prefer-dist laravel/laravel Laravel-Vue
cd Laravel-Vue

Для установки всех необходимых JavaScript-зависимостей, выполним в консоли:

npm init
npm install

Создаем и запускаем миграцию

php artisan make:migration create_tasks_table — create=tasks

Переходим в database/migration и в классе CreateTasksTable вносим следующие изменения:

public function up()
{
Schema::create(‘tasks’, function (Blueprint $table) {
$table->increments(‘id’);
$table->string(‘name’);
$table->unsignedInteger(‘user_id’);
$table->text(‘description’);
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists(‘tasks’);
}

Запускаем миграцию командой:

php artisan migrate

Создаем модель, контроллер и маршруты

Курс Fullstack Web Development.
Стань універсальним розробником, який може створювати веб-рішення з нуля.
Приєднатися

php artisan make:model Task -r

namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Contracts\Validation\Validator;
class Task extends Model
{
protected $fillable = [
‘name’,
‘user_id’,
‘description’,
];

В ресурсном контроллере app\Http\Controllers\TaskController нам пригодятся только четыре метода из семи заготовленных (по сути, мы пишем сильно упрощенную версию API):

<?php
namespace App\Http\Controllers;
use App\Task;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class TaskController extends Controller
{
public function __construct()
{
$this->middleware(‘auth’);
}
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$tasks = Task::where(‘user_id’, Auth::id())->get();
return response()->json(compact(‘tasks’), 200);
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function store(Request $request)
{
$this->validate($request, [
‘name’ => ‘required’,
‘description’ => ‘required’
]);
$task = Task::create([
‘name’ => $request->name,
‘description’ => $request->description,
‘user_id’ => Auth::id()
]);
return response()->json([
‘task’ => $task,
‘message’ => ‘ok’
], 200);
}
/**
* Display the specified resource.
*
* @param \App\Task $task
* @return \Illuminate\Http\Response
*/
public function show(Task $task)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Task $task
* @return \Illuminate\Http\Response
*/
public function edit(Task $task)
{
//
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Task $task
* @return \Illuminate\Http\JsonResponse
*/
public function update(Request $request, Task $task)
{
$task->update($request->all());
return response()->json([
‘message’ => ‘ok!’
], 200);
}
/**
* Remove the specified resource from storage.
*
* @param \App\Task $task
* @return \Illuminate\Http\JsonResponse
*/
public function destroy(Task $task)
{
$task->delete();
return response()->json([
‘message’ => ‘deleted’
], 200);
}
}

В файле route/web.php вносим следующие изменения:

Route::get(‘/home’, ‘HomeController@index’)->name(‘home’);
Route::resource(‘/task’, ‘TaskController’);

Создаем компонент Vue

@extends(‘layouts.app’)
@section(‘content’)
<task></task>
@endsection

Теперь создаем, собственно, компонент Task. В папке resources/js/components нужно создать файл Task.vue:

<template>
<div class=”container”>
<div class=”row”>
<div class=”col-md-12">
<div class=”panel panel-default”>
<div class=”panel-heading”>
<h3><span class=””></span> Task Dashboard </h3> <br>
<button @click=”initAddTask()” class=”btn btn-success “ style=”padding:5px”>
Add new task
</button>
</div>
<div class=”panel-body”>
<table class=”table table-bordered table-striped table-responsive” v-if=”tasks.length > 0">
<tbody>
<tr>
<th>
No.
</th>
<th>
Name
</th>
<th>
Description
</th>
<th>
Action
</th>
</tr>
<tr v-for=”(task, index) in tasks”>
<td>{{ index + 1 }}</td>
<td>
{{ task.name }}
</td>
<td>
{{ task.description }}
</td>
<td>
<button @click=”initUpdate(index)”
title=”edit”
class=”btn btn-success btn-xs”
style=”padding:8px”><span class=”glyphicon glyphicon-edit”></span></button>
<button @click=”deleteTask(index)”
title=”delete”
class=”btn btn-danger btn-xs”
style=”padding:8px”><span class=”glyphicon glyphicon-trash”></span></button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class=”modal fade” tabindex=”-1" role=”dialog” id=”add_task_model”>
<div class=”modal-dialog” role=”document”>
<div class=”modal-content”>
<div class=”modal-header”>
<h4 class=”modal-title”>Add New Task</h4>
<button type=”button” class=”close” data-dismiss=”modal” aria-label=”Close”><span
aria-hidden=”true”>&times;</span></button>
</div>
<div class=”modal-body”>
<div class=”alert alert-danger” v-if=”errors.length > 0">
<ul>
<li v-for=”error in errors”>{{ error }}</li>
</ul>
</div>
<div class=”form-group”>
<label for=”names”>Name:</label>
<input type=”text” name=”name” id=”name” placeholder=”Task Name” class=”form-control”
v-model=”task.name”>
</div>
<div class=”form-group”>
<label for=”description”>Description:</label>
<textarea name=”description” id=”description” cols=”30" rows=”5" class=”form-control”
placeholder=”Task Description” v-model=”task.description”></textarea>
</div>
</div>
<div class=”modal-footer”>
<button type=”button” class=”btn btn-default” data-dismiss=”modal”>Close</button>
<button type=”button” @click=”createTask” class=”btn btn-primary”>Submit</button>
</div>
</div><! — /.modal-content →
</div><! — /.modal-dialog →
</div><! — /.modal →
<div class=”modal fade” tabindex=”-1" role=”dialog” id=”update_task_model”>
<div class=”modal-dialog” role=”document”>
<div class=”modal-content”>
<div class=”modal-header”>
<button type=”button” class=”close” data-dismiss=”modal” aria-label=”Close”><span
aria-hidden=”true”>&times;</span></button>
<h4 class=”modal-title”>Update Task</h4>
</div>
<div class=”modal-body”>
<div class=”alert alert-danger” v-if=”errors.length > 0">
<ul>
<li v-for=”error in errors”>{{ error }}</li>
</ul>
</div>
<div class=”form-group”>
<label>Name:</label>
<input type=”text” placeholder=”Task Name” class=”form-control”
v-model=”update_task.name”>
</div>
<div class=”form-group”>
<label for=”description”>Description:</label>
<textarea cols=”30" rows=”5" class=”form-control”
placeholder=”Task Description” v-model=”update_task.description”></textarea>
</div>
</div>
<div class=”modal-footer”>
<button type=”button” class=”btn btn-default” data-dismiss=”modal”>Close</button>
<button type=”button” @click=”updateTask” class=”btn btn-primary”>Submit</button>
</div>
</div><! — /.modal-content →
</div><! — /.modal-dialog →
</div><! — /.modal →
</div>
</template>
<script>
export default {
data(){
return {
task: {
name: ‘’,
description: ‘’
},
errors: [],
tasks: [],
update_task: {},
upHere: false,
}
},
mounted()
{
this.readTasks();
},
methods: {
deleteTask(index)
{
let conf = confirm(“Do you ready want to delete this task?”);
if (conf === true) {
axios.delete(‘/task/’ + this.tasks[index].id)
.then(response => {
this.tasks.splice(index, 1);
})
.catch(error => {
});
}
},
initAddTask()
{
$(“#add_task_model”).modal(“show”);
},
createTask()
{
axios.post(‘/task’, {
name: this.task.name,
description: this.task.description,
})
.then(response => {
this.reset();
this.tasks.push(response.data.task);
$(“#add_task_model”).modal(“hide”);
})
.catch(error => {
this.errors = [];
if (error.response.data.errors && error.response.data.errors.name) {
this.errors.push(error.response.data.errors.name[0]);
}
if (error.response.data.errors && error.response.data.errors.description)
{
this.errors.push(error.response.data.errors.description[0]);
}
});
},
reset()
{
this.task.name = ‘’;
this.task.description = ‘’;
},
readTasks()
{
axios.get(‘http://127.0.0.1:8000/task')
.then(response => {
this.tasks = response.data.tasks;
});
},
initUpdate(index)
{
this.errors = [];
$(“#update_task_model”).modal(“show”);
this.update_task = this.tasks[index];
},
updateTask()
{
axios.patch(‘/task/’ + this.update_task.id, {
name: this.update_task.name,
description: this.update_task.description,
})
.then(response => {
$(“#update_task_model”).modal(“hide”);
})
.catch(error => {
this.errors = [];
if (error.response.data.errors.name) {
this.errors.push(error.response.data.errors.name[0]);
}
if (error.response.data.errors.description) {
this.errors.push(error.response.data.errors.description[0]);
}
});
}
}
}
</script>
import Task from ‘./components/Task’;
const app = new Vue({
el: ‘#app’,
components: {Task}
});

Приложение готово!

Это текст из личного блога, опубликованный с разрешения автора.

If you have found a spelling error, please, notify us by selecting that text and pressing Ctrl+Enter.

Курс Front-end Basic.
Після успішного закінчення курсу студенти отримують достатньо знань і навичок для верстки сайту будь-якої складності.
Реєстрація на курс

Этот материал – не редакционный, это – личное мнение его автора. Редакция может не разделять это мнение.

Топ-5 самых популярных блогеров февраля

Всего просмотровВсего просмотров
181
#1
Всего просмотровВсего просмотров
181
Senior Project Manager at Nemesis
Всего просмотровВсего просмотров
92
#2
Всего просмотровВсего просмотров
92
Software Architect at Devlify
Всего просмотровВсего просмотров
88
#3
Всего просмотровВсего просмотров
88
Всего просмотровВсего просмотров
68
#4
Всего просмотровВсего просмотров
68
Android Team Lead у Balancуй Team
Всего просмотровВсего просмотров
46
#5
Всего просмотровВсего просмотров
46
Рейтинг блогеров

Ваша жалоба отправлена модератору

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: