آموزش ساخت یک پروژه CRUD ساده توسط Vue.js و لاراول

Vue.js روز به روز محبوب‌تر می‌شود و نکته خوبی که در مورد آن وجود دارد این است می‌توان خیلی سریع شروع به کار با آن کرد. شما می‌توانید با ساخت یک پروژه ساده طبق مراحل این مقاله آموزشی در لیداوب، طرز کار با Vue.js را فرا بگیرید. با ما همراه باشید.


چیزی که ما می‌خواهیم ایجاد کنیم به صورت زیر خواهد بود:

laravel&vue.js

در این آموزش، ما یک پروژه ساده از عملیات CRUD (ایجاد/ خواندن/ ویرایش/ حذف) برای مدیریت کمپانی‌ها ایجاد خواهیم کرد.
ما ابتدا یک پروژه لاراول را ساخته و سپس منطق Vue.js را به آن اضافه می‌کنیم.

آشنایی بیشتر با لاراول و vue.js:

مرحله اول: ایجاد پروژه لاراول

1. یک پروژه لاراول با دستور laravel new یا composer create-project ایجاد می‌کنیم.

2. دستور php artisan make:auth برای داشتن یک Bootstrap نمونه اجرا می‌کنیم.

3. فایل resources/views/auth/login.blade را به یک قالب جدید که لیست شرکت‌ها را نمایش می‌دهد، کپی می‌کنیم که در این پروژه نام آن را

resources / views / admin / companies / index.blade.php قرار دادیم و تمام کدهای داخلی آن را حذف کردیم:

@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="row">
            <div class="col-md-8 col-md-offset-2">
                <div class="panel panel-default">
                    <div class="panel-heading">Companies</div>

                    <div class="panel-body">
                        Coming soon...
                    </div>
                </div>
            </div>
        </div>
    </div>
@endsection

 مرحله دوم: ایجاد لایه بانک اطلاعاتی و API

1. مدل و پایگاه داده خود را با اجرای دستور آرتیسان زیر ایجاد می‌کنیم:

php artisan make:model Company –m

این دستور، فایل app/Company.php ایجاد می‌کند که شما باید با موارد زیر آن را پر کنید:

class Company extends Model
{
protected $fillable = ['name', 'address', 'website', 'email'];
}

و همان فیلدها در یک فایل مایگریشن که از قبل ایجاد شده است:

public function up()
{
Schema::create('companies', function (Blueprint $table) {
$table->increments('id');
$table->string('name')->nullable();
$table->string('address')->nullable();
$table->string('website')->nullable();
$table->string('email')->nullable();
$table->timestamps();
});
}

حالا، اجازه دهید یک کنترلر ایجاد کنیم که تمام عملیات CRUD را مدیریت می‌کند، ولی ما قصد داریم در دستور ساخت کنترلر make:controller آن را به عنوان یک API ذخیره کنیم، چیزی مانند مثال زیر:

laravel controller

بنابراین، دستور ساخت کنترلر ما به صورت زیر خواهد بود:

php artisan make:controller Api/V1/CompaniesController –resource

و ما آن را با یک لیست عملیاتی CRUD به صورت زیر پر می‌کنیم:

namespace App\Http\Controllers\Api\V1;

use App\Company;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class CompaniesController extends Controller
{
    public function index()
    {
        return Company::all();
    }

    public function show($id)
    {
        return Company::findOrFail($id);
    }

    public function update(Request $request, $id)
    {
        $company = Company::findOrFail($id);
        $company->update($request->all());

        return $company;
    }

    public function store(Request $request)
    {
        $company = Company::create($request->all());
        return $company;
    }

    public function destroy($id)
    {
        $company = Company::findOrFail($id);
        $company->delete();
        return '';
    }
}

در نهایت، ما باید مسیرهای برنامه را ایجاد کنیم، در فایل routes/api.php به صورت زیر عمل می‌کنیم:

Route::group(['prefix' => '/v1', 'namespace' => 'Api\V1', 'as' => 'api.'], function () {
Route::resource('companies', 'CompaniesController', ['except' => ['create', 'edit']]);
});

همانطور که مشاهده می‌کنید، ما یک پیشوند api را به استثنای متدهای create و edit اضافه می‌کنیم.
توجه کنید که در این آموزش، هیچ مکانیزم احراز هویت برای API ساخته نشده است، شما باید مسیرهای خود را با بعضی middlewareها یا Laravel Passport محافظت کنید.
حال باید با لایه API کار کنیم، همچنین، برای تست کردن آن نیز می‌توانید از Postman استفاده کنید.

مرحله سوم: شروع کار با Vue.js

برای شروع برنامه نویسی با Vue.js در لاراول، نیازی نیست که آن را نصب کنید، زیرا به صورت آماده از قبل وجود دارد، فایل resources/assets/js/app.js را مشاهده کنید:

/**
* First we will load all of this project's JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/

require('./bootstrap');

window.Vue = require('vue');

/**
* Next, we will create a fresh Vue application instance and attach it to
* the page. Then, you may begin adding components to this application
* or customize the JavaScript scaffolding to fit your unique needs.
*/

Vue.component('example', require('./components/Example.vue'));

const app = new Vue({
el: '#app'
});

در حال حاضر، تمام این کارها یک اپلیکیشن جدید Vue به یک selector با "id = "app اضافه می‌کند که توسط دستور make:auth ساخته شده و در resources/views/layouts/app.blade.php قرار گرفته است:

<body>
    <div id="app">
        <nav class="navbar navbar-default navbar-static-top">
            <div class="container">
...

در حال حاضر، چیزی که ما از Vue نیاز داریم، تنها یک مورد در هسته به نام Vue-router است. این دستور را از پوشه اصلی اجرا می‌کنیم:

npm install && npm install vue-router

مرحله بعدی این است که فایل اصلی Vue.js را کامپایل کنیم. برای انجام این کار، باید دستور زیر را اجرا کنیم:

npm run watch

این فایل resources/assets/js/app.js را به public/js/app.js کامپایل می‌کند که آن هم توسط دستور make:auth ایجاد شده است. قسمت پایین layouts/app.blade.php را مشاهده کنید:

    <!-- Scripts -->
    <script src="{{ asset('js/app.js') }}"></script>
</body>
</html>

دستور npm watch watch نیز یک "watcher" را راه اندازی می‌کند که در زمان تغییر فایل‌ها، آن‌ها را کامپایل می‌کند.

مرحله چهارم: Vue-router و Index / List Component

مرحله بعدی این است که از Vue-router استفاده کنید و آن را به ویوهای مختلف در CRUD اختصاص دهید.

ابتدا، اجازه دهید فایل resources/views/admin/companies/index.blade.php را باز کرده و router را بارگذاری کنیم:

...
<div class="panel-heading">Companies</div>

<div class="panel-body table-responsive">
    <router-view name="companiesIndex"></router-view>
    <router-view></router-view>
</div>
...
 خطوط کد router-view را مشاهده کنید، این دقیقا همان جایی است که companiesIndex در آن لود خواهند شد. حال، بیایید این کار را انجام دهیم.

فایل resources/assets/js/app.js را باز کرده و محتوای زیر را در آن قرار دهید، هر قسمت از کد در بخش‌های پایین‌تر توضیح داده خواهد شد:

/**
* First we will load all of this project's JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/

require('./bootstrap');

window.Vue = require('vue');
import VueRouter from 'vue-router';

window.Vue.use(VueRouter);

import CompaniesIndex from './components/companies/CompaniesIndex.vue';
import CompaniesCreate from './components/companies/CompaniesCreate.vue';
import CompaniesEdit from './components/companies/CompaniesEdit.vue';

const routes = [
{
path: '/',
components: {
companiesIndex: CompaniesIndex
}
},
{path: '/admin/companies/create', component: CompaniesCreate, name: 'createCompany'},
{path: '/admin/companies/edit/:id', component: CompaniesEdit, name: 'editCompany'},
]

const router = new VueRouter({ routes })

const app = new Vue({ router }).$mount('#app')

برای کسب اطلاعات کلی در مورد نحوه کار Router، می‌توانید مستندات Vue را بررسی کنید. کاری که ما در اینجا انجام می‌دهیم، افزودن route موردنیاز به کامپوننت Vue است، مانند CompaniesIndex، CompaniesCreate، CompaniesEdit. حال، اجازه دهید آن‌ها را ایجاد کنیم.

در اینجا، یک فایل resources/assets/js/components/companies/CompaniesIndex.vue وجود دارد:

<template>
    <div>
        <div class="form-group">
            <router-link :to="{name: 'createCompany'}" class="btn btn-success">Create new company</router-link>
        </div>

        <div class="panel panel-default">
            <div class="panel-heading">Companies list</div>
            <div class="panel-body">
                <table class="table table-bordered table-striped">
                    <thead>
                    <tr>
                        <th>Name</th>
                        <th>Address</th>
                        <th>Website</th>
                        <th>Email</th>
                        <th width="100">&nbsp;</th>
                    </tr>
                    </thead>
                    <tbody>
                    <tr v-for="company, index in companies">
                        <td>{{ company.name }}</td>
                        <td>{{ company.address }}</td>
                        <td>{{ company.website }}</td>
                        <td>{{ company.email }}</td>
                        <td>
                            <router-link :to="{name: 'editCompany', params: {id: company.id}}" class="btn btn-xs btn-default">
                                Edit
                            </router-link>
                            <a href="#"
                               class="btn btn-xs btn-danger"
                               v-on:click="deleteEntry(company.id, index)">
                                Delete
                            </a>
                        </td>
                    </tr>
                    </tbody>
                </table>
            </div>
        </div>
    </div>
</template>

<script>
    export default {
        data: function () {
            return {
                companies: []
            }
        },
        mounted() {
            var app = this;
            axios.get('/api/v1/companies')
                .then(function (resp) {
                    app.companies = resp.data;
                })
                .catch(function (resp) {
                    console.log(resp);
                    alert("Could not load companies");
                });
        },
        methods: {
            deleteEntry(id, index) {
                if (confirm("Do you really want to delete it?")) {
                    var app = this;
                    axios.delete('/api/v1/companies/' + id)
                        .then(function (resp) {
                            app.companies.splice(index, 1);
                        })
                        .catch(function (resp) {
                            alert("Could not delete company");
                        });
                }
            }
        }
    }
</script>

این همان جدولی است که در index.blade.php ظاهر می‌شود فقط با روش Vue.js.

• کد  <router-link :to=”{name: ‘createCompany’}”>  یک لینک به کامپوننتی که لود می‌کند بدون بارگذاری کل صفحه، ایجاد می‌کند.
• ردیف جدول  <tr v-for=”company, index in companies”>  داده‌ها را بارگذاری کرده و هر فیلد را در آنجا نمایش می‌دهد.
• داده‌ها برای جدول از API از طریق JS با دستور زیر دریافت می‌شود:
axios.get(‘/api/v1/companies’) -> app.companies = resp.data
• همچنین، یک رویداد برای دکمه Delete وجود دارد که متد API delete را فراخوانی کرده و جدول را دوباره لود می‌کند (نه کل صفحه را): axios.delete(‘/api/v1/companies/’ + id)

در واقع، این برای لیست شرکت‌هاست، جدول خالی را بارگذاری کرده و سپس آن را با داده‌های API پر می‌کند.

مرحله پنجم: ایجاد و ویرایش کامپوننت‌های Vue

اکنون، شما می‌دانید که کامپوننت‌های Vue چه هستند و چگونه می‌توان آن‌ها را به URLها از طریق VueRouter الحاق کرد. اجازه دهید دموی پروژه را با فرم‌های create و edit تکمیل کنیم.

در فایل resources/assets/js/components/companies/CompaniesCreate.vue:

<template>
    <div>
        <div class="form-group">
            <router-link to="/" class="btn btn-default">Back</router-link>
        </div>

        <div class="panel panel-default">
            <div class="panel-heading">Create new company</div>
            <div class="panel-body">
                <form v-on:submit="saveForm()">
                    <div class="row">
                        <div class="col-xs-12 form-group">
                            <label class="control-label">Company name</label>
                            <input type="text" v-model="company.name" class="form-control">
                        </div>
                    </div>
                    <div class="row">
                        <div class="col-xs-12 form-group">
                            <label class="control-label">Company address</label>
                            <input type="text" v-model="company.address" class="form-control">
                        </div>
                    </div>
                    <div class="row">
                        <div class="col-xs-12 form-group">
                            <label class="control-label">Company website</label>
                            <input type="text" v-model="company.website" class="form-control">
                        </div>
                    </div>
                    <div class="row">
                        <div class="col-xs-12 form-group">
                            <label class="control-label">Company email</label>
                            <input type="text" v-model="company.email" class="form-control">
                        </div>
                    </div>
                    <div class="row">
                        <div class="col-xs-12 form-group">
                            <button class="btn btn-success">Create</button>
                        </div>
                    </div>
                </form>
            </div>
        </div>
    </div>
</template>

<script>
    export default {
        data: function () {
            return {
                company: {
                    name: '',
                    address: '',
                    website: '',
                    email: '',
                }
            }
        },
        methods: {
            saveForm() {
                event.preventDefault();
                var app = this;
                var newCompany = app.company;
                axios.post('/api/v1/companies', newCompany)
                    .then(function (resp) {
                        app.$router.push({path: '/'});
                    })
                    .catch(function (resp) {
                        console.log(resp);
                        alert("Could not create your company");
                    });
            }
        }
    }
</script>
 چیزهایی که در اینجا وجود دارند:
  • template> tag for the main content and <script> for the JS part>
  • اختصاص دادن فیلدهای ورودی به فیلدهای مدل: "input type = "text" v-model = "company.name
  • فرم با رویداد ارسال "()v-on:submit=”saveForm و متد تعریف شده با فراخوانی API  (axios.delete(‘/api/v1/companies/’ + id

پس از ارسال فرم Vue.js جدول اصلی دوباره بارگذاری می‌شود، اما این بار بدون بارگذاری کل صفحه.

در نهایت، ویرایش فایل resources/assets/js/components/companies/CompaniesEdit.vue که مشابه قسمت‌های قبل است و در اینجا فقط بخش JS نمایش داده شده است:

<script>

    export default {

        mounted() {

            let app = this;

            let id = app.$route.params.id;

            app.companyId = id;

            axios.get('/api/v1/companies/' + id)

                .then(function (resp) {

                    app.company = resp.data;

                })

                .catch(function () {

                    alert("Could not load your company")

                });

        },

        data: function () {

            return {

                companyId: null,

                company: {

                    name: '',

                    address: '',

                    website: '',

                    email: '',

                }

            }

        },

        methods: {

            saveForm() {

                event.preventDefault();

                var app = this;

                var newCompany = app.company;

                axios.patch('/api/v1/companies/' + app.companyId, newCompany)

                    .then(function (resp) {

                        app.$router.replace('/');

                    })

                    .catch(function (resp) {

                        console.log(resp);

                        alert("Could not create your company");

                    });

            }

        }

    }

</script>

 می‌توانید این پروژه را در GitHub امتحان کنید.

امیدوارم این مقاله از سری مقالات کاربردی فریم ورک لاراول در لیداوب نیز به شما در طراحی سایت‌های حرفه‌ای با این فریم ورک کمک کند. می‌توانید مقالات آموزشی و دوره‌های اموزشی ما در زمینه برنامه نویسی با PHP، لاراول، HTML و CSS در لیداوب دنبال کنید. همچنین ما مشتاق دریافت نظرات و سوالات شما در بخش کامنت‌ها هستیم.