Всем привет! В этой статье я предлагаю вам написать вместе со мной простое одностраничное приложение меньше, чем за час. Для этого воспользуемся веб-фреймворком Laravel, который по умолчанию включает в себя популярный фронтенд-фреймворк Vue.js.
Прежде всего, установим свежий экземпляр Laravel:
composer create-project — prefer-dist laravel/laravel Laravel-Vue cd Laravel-Vue
Для установки всех необходимых JavaScript-зависимостей, выполним в консоли:
npm init npm install
Далее убедитесь, что в файле .env
указаны правильные данные для соединения с базой.
Создаем и запускаем миграцию
Откройте терминал и в корне проекта выполните следующую команду:
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
Создаем модель, контроллер и маршруты
Для этого выполняем команду:
php artisan make:model Task -r
Флаг -r
указывает, что нам нужен ресурсный контроллер. Другими словами, нам лень вручную писать названия всех CRUD-методов.
В теле вновь созданной модели app/Task
укажем поля, которые будут доступны для массового заполнения:
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’);
Route::resource
создает полный список CRUD-маршрутов. Маршрут /home
нам понадобится для вывода шаблона, внутри которого мы разместим нужные vue-компоненты.
Создаем компонент Vue
В файле resources/views/home.blade.php
вносим следующие изменения:
@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”>×</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”>×</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>
Регистрируем компонент в базовом JS-файле resources/js/app.js
.
Добавьте следующие строки:
import Task from ‘./components/Task’; const app = new Vue({ el: ‘#app’, components: {Task} });
Еще раз npm run dev
.
Теперь запускаем сервер: php artisan serve
.
После регистрации пользователя попадаем на страничку /home
:
Приложение готово!
Это текст из личного блога, опубликованный с разрешения автора.
Этот материал – не редакционный, это – личное мнение его автора. Редакция может не разделять это мнение.
Сообщить об опечатке
Текст, который будет отправлен нашим редакторам: