مقالات/فیلمهای زیادی در Laravel + Vue CRUD وجود دارد ، اما تعداد کافی در جدیدترین نسخه Vue.js 3 با استفاده از API جدید Composition منتشر نشده است. بنابراین ، با این مقاله مفصل گام به گام ، بیایید این شکاف را پر کرده و یک فرم مدیریت ساده شرکت ایجاد کنیم.

Laravel و Laravel Breeze را نصب کنید

ما از ابتدا با نصب یک پروژه جدید Laravel و a نسیم لاراول کیت استارت:

laravel new project
cd project
// editing .env file here
composer install
php artisan migrate
composer require laravel/breeze
compose require breeze:install
npm install && npm run dev

در این مرحله ، ما باید یک پیش فرض Laravel Breeze با طراحی CSS Tailwind و قابلیت ورود/ثبت نام داشته باشیم:

ایجاد مدل و API CRUD

ما یک جدول به نام مدیریت می کنیم شرکت ها، با چهار فیلد متنی: نام، پست الکترونیک، نشانی، سایت اینترنتیبه

بنابراین ، ما مدل را ایجاد می کنیم و به طور خودکار مهاجرت ها را با :

php artisan make:model Company -m

این ساختار DB است: database/migrations/xxxxx_create_companies_table.php:

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

    public function down()
    {
        Schema::dropIfExists('companies');
    }
}

در app/Company.php مدل ، همه فیلدها را پر می کنیم:

class Company extends Model
{
    use HasFactory;

    protected $fillable = ['name', 'email', 'address', 'website'];
}

بعد ، ما یک Controller ، با ، ایجاد می کنیم چند پرچم برای تولید دقیقاً آنچه ما نیاز داریم:

php artisan make:controller Api/CompanyController --resource --api --model=Company

شخصاً دوست دارم استفاده کنم منابع API برای تبدیل داده ها اگرچه در این پروژه ، ما هیچ تغییری ایجاد نمی کنیم ، اما من هنوز عادت دارم آنها را ایجاد کنم:

php artisan make:resource CompanyResource

و ، در داخل app/Http/Resources/CompanyResource.php، این کد پیش فرض وجود دارد:

class CompanyResource extends JsonResource
{
    public function toArray($request)
    {
        return parent::toArray($request);
    }
}

بعد ، برای اعتبار سنجی ، یک کلاس FormRequest ایجاد می کنیم:

php artisan make:request CompanyRequest

در این مورد ، من مجدداً از قوانین اعتبارسنجی یکسانی برای هر دو عملکرد store/update استفاده می کنم ، بنابراین این محتویات آن است app/Http/Requests/CompanyRequest.php:

class CompanyRequest extends FormRequest
{
    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        return [
            'name' => ['required', 'string'],
            'email' => ['required', 'email'],
            'address' => ['nullable', 'string'],
            'website' => ['nullable', 'url'],
        ];
    }
}

ما از کلاسهای API Resource و Form Request در داخل کلاسهای خود استفاده می کنیم app/Http/Controllers/API/CompanyController.php، که دارای این کد است:

namespace AppHttpControllersApi;

use AppHttpControllersController;
use AppHttpRequestsCompanyRequest;
use AppHttpResourcesCompanyResource;
use AppModelsCompany;

class CompanyController extends Controller
{
    public function index()
    {
        return CompanyResource::collection(Company::all());
    }

    public function store(CompanyRequest $request)
    {
        $company = Company::create($request->validated());

        return new CompanyResource($company);
    }

    public function show(Company $company)
    {
        return new CompanyResource($company);
    }

    public function update(CompanyRequest $request, Company $company)
    {
        $company->update($request->validated());

        return new CompanyResource($company);
    }

    public function destroy(Company $company)
    {
        $company->delete();

        return response()->noContent();
    }
}

و ما همه را با هم گره می زنیم تا آن کنترلر را از route/api.php:

use AppHttpControllersApiCompanyController;

// ...

Route::apiResource('companies', CompanyController::class);

در این پروژه ساده ، ما از هیچ Middleware استفاده نخواهیم کرد ، مسیرها عمومی هستند.

بنابراین ، در این مرحله ، ما یک API آماده داریم ، و اگر شرکتی را به صورت دستی در DB وارد کنیم ، در اینجا چیزی است که از طریق پستچی دریافت می کنیم:


نصب Vue و “Hello World”

اکنون ، ما به بخش جلویی می رسیم. ما Vue.js ، Vue Router و Vue Loader را نصب می کنیم:

npm install vue@next vue-router@next vue-loader@next

اگر استفاده نمی کنید @بعد، نسخه قدیمی Vue.js 2 را نصب می کند ، این چیزی نیست که ما در این مقاله می خواهیم ، ما می خواهیم از Vue 3 با API Composition استفاده کنیم.

در مرحله بعد ، ما باید برنامه را فعال کنیم view-loader، و در webpack.mix.js ما باید اضافه کنیم مشاهده گردید() قسمتی که باید تدوین شود

قبل از:

mix.js('resources/js/app.js', 'public/js').postCss(...

بعد از:

mix.js('resources/js/app.js', 'public/js').vue().postCss(...

اکنون ، ما باید اولین جزء Vue.js خود را ایجاد کنیم. در حال حاضر ، هیچ کار پویایی انجام نمی دهد ، فقط “سلام جهان” را نشان دهید ، در منابع/js/اجزا/شرکتها/CompaniesIndex.vue:

<template>
    Hello world.
</template>

این در این فایل است ، در حال حاضر ، ما هیچ اضافه نمی کنیم <اسکریپت> عنصر ، در قسمت بعدی به آن قسمت می رسیم.

اکنون ، اجازه دهید فایل مسیرهای خود را ایجاد کنیم. ما سه مسیر خواهیم داشت: نمایه سازی شرکت ، ایجاد و ویرایش فرم ها. اما ، در حال حاضر ، بیایید به اولین مورد بمانیم ، در اینجا نحو نسخه Vue.js 3 است منابع/js/route/index.js:

import { createRouter, createWebHistory } from 'vue-router'

import CompaniesIndex from '../components/companies/CompaniesIndex.vue'

const routes = [
    {
        path: '/dashboard',
        name: 'companies.index',
        component: CompaniesIndex
    }
];

export default createRouter({
    history: createWebHistory(),
    routes
})

بعد ، ما را اضافه می کنیم id = ”برنامه” در فایل اصلی Blade پروژه ما resources/views/layouts/app.blade.php:

<body class="font-sans antialiased">
    <div class="min-h-screen bg-gray-100" id="app">

اکنون ، ما می توانیم برنامه Vue خود را در داخل آن ایجاد کنیم #برنامه، در اینجا نحو نسخه Vue 3 برای آن وجود دارد ، در منابع/js/app.js:

require('./bootstrap');

require('alpinejs');

import { createApp } from 'vue';
import router from './router'

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

createApp({
    components: {
        CompaniesIndex
    }
}).use(router).mount('#app')

بعد ، بیایید نمای Laravel را آماده کنیم تا شامل عملکرد Vue باشد. ما باید این خط را به route/web.php فایل ، که داشبورد را در هر نمای دیگری که از Vue Router می آید بارگذاری می کند:

Route::view('/{any}', 'dashboard')
    ->middleware(['auth'])
    ->where('any', '.*');

ما فایل پیش فرض Laravel Breeze را تغییر می دهیم resources/views/dashboard.blade.php شامل برچسب:

<x-app-layout>
    <x-slot name="header">
       ...
    </x-slot>

    <div class="py-12">
        <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
            <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
                <div class="p-6 bg-white border-b border-gray-200">
                    <router-view />
                </div>
            </div>
        </div>
    </div>
</x-app-layout>

تمام شد ، بیایید دستور اصلی را برای کامپایل همه آن اجرا کنیم:

npm run dev
// or "npm run watch" to watch for changes in live-mode

بنابراین ، اکنون ، پس از ورود به داشبورد Laravel Breeze ، باید این را ببینید:

خوب ، ما Vue.js را در پروژه خود فعال کردیم!


فهرست شرکت ها: API Composition

در Vue 3 ، راه ایجاد اجزاء با معرفی API Composition تغییر کرد. به شما این امکان را می دهد که قسمت های م theلفه را به فایل های جداگانه تقسیم کرده و مجدداً مورد استفاده قرار دهید. مشکل در پروژه های بزرگتر ظاهر می شود ، اما من توصیه می کنم از آن حتی در پروژه های کوچکتر مانند این استفاده کنید تا عادت به جداسازی نگرانی ها داشته باشید و کد را بیشتر خوانا کنید.

بنابراین اگر با سابقه Vue 2 به اینجا آمده اید ، کد زیر برای شما چندان آشنا به نظر نمی رسد ، بنابراین لطفاً اسناد رسمی Vue را در Why Composition API، و همچنین این مقاله: API Vue 3 Composition در مقابل API گزینه هابه

اطلاع: هنوز می توانید از “روش قدیمی” اجزا در Vue 3 نیز استفاده کنید ، اما هنگام آماده شدن برای این مقاله ، من از مخاطبان توییتر خود پرسیدم و بسیاری از افرادی که Vue 3 دارند در واقع از API Composition استفاده می کنند:

برای داشتن CRUD شرکت ها ، ما از یک API Composition به نام استفاده می کنیم ترکیب پذیر، که یک فایل جداگانه است که شامل تمام روشهای مورد نیاز ما می شود. در صورت تمایل ، مانند سرویس در Laravel است.

بنابراین ، ما ایجاد می کنیم منابع/js/ترکیبات/شرکت ها. js، با این کد:

import { ref } from 'vue'
import axios from 'axios'
import { useRouter } from 'vue-router'

export default function useCompanies() {
    const company = ref([])
    const companies = ref([])

    const errors = ref('')
    const router = useRouter()

    const getCompanies = async () => {
        let response = await axios.get('/api/companies')
        companies.value = response.data.data
    }

    const getCompany = async (id) => {
        let response = await axios.get(`/api/companies/${id}`)
        company.value = response.data.data
    }

    const storeCompany = async (data) => {
        errors.value=""
        try {
            await axios.post('/api/companies', data)
            await router.push({ name: 'companies.index' })
        } catch (e) {
            if (e.response.status === 422) {
                for (const key in e.response.data.errors) {
                    errors.value += e.response.data.errors[key][0] + ' ';
                }
            }
        }

    }

    const updateCompany = async (id) => {
        errors.value=""
        try {
            await axios.patch(`/api/companies/${id}`, company.value)
            await router.push({ name: 'companies.index' })
        } catch (e) {
            if (e.response.status === 422) {
                for (const key in e.response.data.errors) {
                    errors.value += e.response.data.errors[key][0] + ' ';
                }
            }
        }
    }

    return {
        errors,
        company,
        companies,
        getCompany,
        getCompanies,
        storeCompany,
        updateCompany
    }
}

در اینجا چند نکته قابل توجه است.

نام استاندارد معمول عملکرد Composable است useSomething ()، و لزوما نیازی نیست که همانند نام فایل باشد.

بعد ، ما استفاده می کنیم axios برای درخواست های API ، که به طور پیش فرض در نصب Laravel گنجانده شده است ، ما فقط باید آن را وارد کنیم و می توانیم درخواست هایی مانند axios.get () و axios.post ()به

بعد ، آن چیست؟ مرجع چیز؟ این عبارت برای “مرجع” کوتاهتر است ، و همانطور که در آن گفته شده است مستندات رسمی Vue 3، “در Vue 3.0 ما می توانیم هر متغیری را در هر مکانی با یک جدید واکنش پذیر کنیم ref عملکرد”. بنابراین ، وقتی متغیرهای خود را برای مثال تعریف می کنیم ، const company = ref ([]) نحو ، اکنون هر زمان که تماس می گیریم getCompanies، companies تغییر می کند و نمای به روز می شود تا تغییر را نشان دهد.

نکته بعدی که باید به آن توجه کنید این است که ما از Vue Router برای هدایت به لیست با نام آن استفاده می کنیم company.index، پس از روش ذخیره/بروز رسانی موفق. در صورت اشتباه در اعتبار سنجی با کد 422، ساختار خطا را تجزیه کرده و آن را به متغیر String از تبدیل می کنیم خطاهابه

در نهایت ، آنچه را که از فایل Composable برمی گردانیم تعریف می کنیم – همه متغیرها و روش ها.

حالا ، بیایید آنها را در مورد خود پر کنیم منابع/js/اجزا/شرکتها/CompaniesIndex.vue با جدول واقعی اطلاعات مربوط به شرکت ها. در اینجا کد به روز شده ما ، جدول در <الگو> part و Composition API در <اسکریپت> بخش

<template>
    <div class="overflow-hidden overflow-x-auto min-w-full align-middle sm:rounded-md">
        <table class="min-w-full border divide-y divide-gray-200">
            <thead>
            <tr>
                <th class="px-6 py-3 bg-gray-50">
                    <span
                        class="text-xs font-medium tracking-wider leading-4 text-left text-gray-500 uppercase">Name</span>
                </th>
                <th class="px-6 py-3 bg-gray-50">
                    <span
                        class="text-xs font-medium tracking-wider leading-4 text-left text-gray-500 uppercase">Email</span>
                </th>
                <th class="px-6 py-3 bg-gray-50">
                    <span
                        class="text-xs font-medium tracking-wider leading-4 text-left text-gray-500 uppercase">Address</span>
                </th>
                <th class="px-6 py-3 bg-gray-50">
                    <span
                        class="text-xs font-medium tracking-wider leading-4 text-left text-gray-500 uppercase">Website</span>
                </th>
            </tr>
            </thead>

            <tbody class="bg-white divide-y divide-gray-200 divide-solid">
            <template v-for="item in companies" :key="item.id">
                <tr class="bg-white">
                    <td class="px-6 py-4 text-sm leading-5 text-gray-900 whitespace-no-wrap">
                        {{ item.name }}
                    </td>
                    <td class="px-6 py-4 text-sm leading-5 text-gray-900 whitespace-no-wrap">
                        {{ item.email }}
                    </td>
                    <td class="px-6 py-4 text-sm leading-5 text-gray-900 whitespace-no-wrap">
                        {{ item.address }}
                    </td>
                    <td class="px-6 py-4 text-sm leading-5 text-gray-900 whitespace-no-wrap">
                        {{ item.website }}
                    </td>
                </tr>
            </template>
            </tbody>
        </table>
    </div>
</template>

<script>
import useCompanies from '../../composables/companies'
import { onMounted } from 'vue';

export default {
    setup() {
        const { companies, getCompanies } = useCompanies()

        onMounted(getCompanies)

        return {
            companies,
        }
    }
}
</script>

جدول نیازی به اظهارنظر زیاد ندارد ، فقط حلقه foreach را با این نحو انجام می دهد:

<template v-for="item in companies" :key="item.id">
  <tr>
    <td>{{ item.property }}</td>
  </tr>
</template>

حال ، چگونه می توانیم آن را بدست آوریم شرکت ها متغیر؟ من برخی از نظرات را با قسمت اسکریپت اضافه می کنم:

<script>
// Here we're using a Composable file here, its code is above
import useCompanies from '../../composables/companies'

// onMounted will define what method to "fire" automatically
import { onMounted } from 'vue';

export default {
    // This is a Vue 3 syntax to define the component setup()
    setup() {
        // We need only two things from the useCompanies() composable
        const { companies, getCompanies } = useCompanies()

        // We get the companies immediately
        onMounted(getCompanies)

        return {
            companies, // and return them to use in <template>
        }
    }
}
</script>

و بعد از دویدن npm اجرا dev (یا باز هم اگر دارید ساعت اجرا npm فعال) ، ما این را در داشبورد مشاهده می کنیم:

ببینید ، API Composition چندان دشوار نیست؟ حالا بیایید یک روش دیگر به آن اضافه کنیم.


دکمه ای برای حذف شرکت

برخلاف مقالات رایج CRUD که Delete آخرین مورد است ، من می خواهم آن را بلافاصله پیاده سازی کنم ، زیرا کوتاه خواهد بود و قدرت Composition API را نشان می دهد.

در فایل Composable منابع/js/composable/company.js ما یک روش دیگر اضافه می کنیم که Delete API endpoint را فراخوانی می کند. همچنین ، ما باید آن روش را در پایین برگردانیم:

    const destroyCompany = async (id) => {
        await axios.delete(`/api/companies/${id}`)
    }

    return {
        errors,
        company,
        // ...
        destroyCompany
    }

اکنون ، می توانیم آن متد را از کامپوننت خود فراخوانی کنیم. بنابراین ، در منابع/js/اجزا/شرکتها/CompaniesIndex.vue ما یک دکمه در قالب اضافه می کنیم ، با متد در اسکریپت:

<template>
...

<th class="bg-gray-50"></th>

...

<td class="px-6 py-4 text-sm text-center leading-5 text-gray-900 whitespace-no-wrap">
    <button @click="deleteCompany(item.id)"
            class="inline-flex items-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 active:bg-gray-900 focus:outline-none focus:border-gray-900 focus:ring ring-gray-300 disabled:opacity-25 transition ease-in-out duration-150">
            Delete</button>
</td>

</template>

<script>
export default {
    setup() {
        const { companies, getCompanies, destroyCompany } = useCompanies()

        const deleteCompany = async (id) => {
            if (!window.confirm('You sure?')) {
                return
            }

            await destroyCompany(id)
            await getCompanies()
        }

        onMounted(getCompanies)

        return {
            companies,
            deleteCompany
        }
    }
}
</script>

بخش قالب کاملاً واضح است ، ما فقط اضافه می کنیم button @click = ”deleteCompany (item.id)” آنجا.

بخش فیلمنامه جالب تر است. اضافه می کنیم خراب کردن شرکت برای دریافت از فایل Composable ، ما یک روش محلی نیز تعریف می کنیم حذف شرکت، که به نوبه خود آن روش ترکیبی را می نامد خراب کردن شرکت، و سپس تماس می گیرد getCompanies دوباره ، برای تازه کردن جدول. بنابراین ، ببینید ، چگونه از فایل Composable مجدداً بدون آلوده کردن اجزای اصلی استفاده می کنیم؟ این یکی از مزایای Composition API است.

همچنین ، ببینید که ما باید لیست را نشان دهیم حذف شرکت در بازگشت از برپایی() متد ، در غیر این صورت در قسمت قالب ، برای دکمه ما قابل مشاهده نخواهد بود.

این برای این بخش تمام شده است ، ما دکمه حذف را فعال کرده ایم!

ایجاد شرکت: مسیر ، فرم ، اعتبار سنجی

بعد ، در بالای جدول ، اجازه دهید دکمه ای را اضافه کنیم که به فرم ایجاد یک شرکت جدید منجر می شود. در حال حاضر ، اجازه دهید یک جزء خالی در ایجاد کنیم منابع/js/اجزا/شرکتها/CompaniesCreate.vue:

<template>
    Create form coming soon.
</template>

در مرحله بعد ، ما یک مسیر به resources/js/router/index.js:

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

const routes = [
    {
        path: '/dashboard',
        name: 'companies.index',
        component: CompaniesIndex
    },
    {
        path: '/companies/create',
        name: 'companies.create',
        component: CompaniesCreate
    },
];

در نهایت ، یک دکمه در بالای جدول اضافه می کنیم ، با لینک روتر، در منابع/js/اجزا/شرکتها/CompaniesCreate.vue:

<template>
    <div class="flex place-content-end mb-4">
        <div class="px-4 py-2 text-white bg-indigo-600 hover:bg-indigo-700 cursor-pointer">
            <router-link :to="{ name: 'companies.create' }" class="text-sm font-medium">Create company</router-link>
        </div>
    </div>

    <div class="overflow-hidden overflow-x-auto min-w-full align-middle sm:rounded-md">

توجه داشته باشید که ما مسیر را بر اساس آن می نامیم نام – همان موردی که در فایل route ها تعریف کردیم.

بنابراین ، در حال حاضر ، دکمه ما به این شکل است:

منجر به صفحه ای می شود که فعلاً خالی است:

اکنون ، ما آن را با فرم و اسکریپت برای پردازش آن فرم پر می کنیم ، در اینجا کد کامل آن آمده است منابع/js/اجزا/شرکتها/CompaniesCreate.vue:

<template>
    <div class="mt-2 mb-6 text-sm text-red-600" v-if="errors !== ''">
        {{ errors }}
    </div>

    <form class="space-y-6" @submit.prevent="saveCompany">
        <div class="space-y-4 rounded-md shadow-sm">
            <div>
                <label for="name" class="block text-sm font-medium text-gray-700">Name</label>
                <div class="mt-1">
                    <input type="text" name="name" id="name"
                           class="block mt-1 w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
                           v-model="form.name">
                </div>
            </div>

            <div>
                <label for="email" class="block text-sm font-medium text-gray-700">Email</label>
                <div class="mt-1">
                    <input type="text" name="email" id="email"
                           class="block mt-1 w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
                           v-model="form.email">
                </div>
            </div>

            <div>
                <label for="address" class="block text-sm font-medium text-gray-700">Address</label>
                <div class="mt-1">
                    <input type="text" name="address" id="address"
                           class="block mt-1 w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
                           v-model="form.address">
                </div>
            </div>

            <div>
                <label for="website" class="block text-sm font-medium text-gray-700">Website</label>
                <div class="mt-1">
                    <input type="text" name="website" id="website"
                           class="block mt-1 w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
                           v-model="form.website">
                </div>
            </div>
        </div>

        <button type="submit"
                class="inline-flex items-center px-4 py-2 text-xs font-semibold tracking-widest text-white uppercase bg-gray-800 rounded-md border border-transparent ring-gray-300 transition duration-150 ease-in-out hover:bg-gray-700 active:bg-gray-900 focus:outline-none focus:border-gray-900 focus:ring disabled:opacity-25">
            Create
        </button>
    </form>
</template>

<script>
import useCompanies from '../../composables/companies'
import { reactive } from 'vue'

export default {
    setup() {
        const form = reactive({
            name: '',
            email: '',
            address: '',
            website: ''
        })

        const { errors, storeCompany } = useCompanies()

        const saveCompany = async () => {
            await storeCompany({ ...form })
        }

        return {
            form,
            errors,
            saveCompany
        }
    }
}
</script>

در قالب بخش ، مهمترین بخشها هستند <فرم @submit.prevent= ”saveCompany”> و سپس هر زمینه دارای مدل v= ”فرم.[field_name]”، اتصال آن به فرم هدف – شی.

که فرم در زیر شرح داده شده است ، در اسکریپت بخش ، با مقادیر پیش فرض:

const form = reactive({
    name: '',
    email: '',
    address: '',
    website: ''
})

این واکنشی چیزی که باید با آن وارد کنیم وارد کردن {reactive} از “vue”، بسیار شبیه به است مرجع که در بالا بحث کردیم ، اما مقدار داخلی باید به جای یک مقدار واحد ، داده هایی با ساختار فرهنگ لغت مانند شی JS باشد.

بعد ، saveCompany () متد یک روش اجزای محلی خواهد بود که به نوبه خود روش Composable را نام می برد ایجاد شرکت ()به

در صورت وجود خطاهای اعتبار سنجی ، ما داریم خطاها رشته با تمام خطاها ، با علامت فاصله از هم جدا شده است. نتیجه به این شکل است:

و اگر همه چیز خوب پیش رفت ، ما به طور خودکار (اما بدون بارگذاری مجدد صفحه کامل) به لیست شرکت ها هدایت می شویم. در فایل Composable ، توسط router.push ({name: ‘company.index’})به

فرم ویرایش/به روز رسانی شرکت

فرم ویرایش تقریباً با فرم ویرایش یکسان خواهد بود و تنها چند تفاوت دارد.

اول ، جزء خالی منابع/js/اجزا/شرکتها/CompaniesEdit.vue:

<template>
    Edit form coming soon.
</template>

بعد ، مسیر داخل resources/js/router/index.js – این بار با یک پارامتر :شناسه و با تنظیم لوازم: درست است:

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

const routes = [
    {
        path: '/dashboard',
        name: 'companies.index',
        component: CompaniesIndex
    },
    {
        path: '/companies/create',
        name: 'companies.create',
        component: CompaniesCreate
    },
    {
        path: '/companies/:id/edit',
        name: 'companies.edit',
        component: CompaniesEdit,
        props: true
    },
];

سپس ، یک دکمه برای ویرایش یک رکورد خاص در منابع/js/اجزا/شرکتها/CompaniesIndex.vue:

<td class="px-6 py-4 text-sm text-center leading-5 text-gray-900 whitespace-no-wrap">
    <router-link :to="{ name: 'companies.edit', params: { id: item.id } }"
                 class="mr-2 ...">Edit</router-link>
    <button @click="deleteCompany(item.id)"
              class="...">Delete</button>
</td>

در اینجا نتیجه بصری است:

و وقتی روی Edit کلیک می کنیم ، همانطور که انتظار می رود این را می بینیم:

حالا بیایید فرم واقعی را بسازیم. در اینجا کد مربوط به منابع/js/اجزا/شرکتها/CompaniesEdit.vue:

<template>
    <div class="mt-2 mb-6 text-sm text-red-600" v-if="errors !== ''">
        {{ errors }}
    </div>

    <form class="space-y-6" v-on:submit.prevent="saveCompany">
        <div class="space-y-4 rounded-md shadow-sm">
            <div>
                <label for="name" class="block text-sm font-medium text-gray-700">Name</label>
                <div class="mt-1">
                    <input type="text" name="name" id="name"
                           class="block mt-1 w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
                           v-model="company.name">
                </div>
            </div>

            <div>
                <label for="email" class="block text-sm font-medium text-gray-700">Email</label>
                <div class="mt-1">
                    <input type="text" name="email" id="email"
                           class="block mt-1 w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
                           v-model="company.email">
                </div>
            </div>

            <div>
                <label for="address" class="block text-sm font-medium text-gray-700">Address</label>
                <div class="mt-1">
                    <input type="text" name="address" id="address"
                           class="block mt-1 w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
                           v-model="company.address">
                </div>
            </div>

            <div>
                <label for="website" class="block text-sm font-medium text-gray-700">Website</label>
                <div class="mt-1">
                    <input type="text" name="website" id="website"
                           class="block mt-1 w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
                           v-model="company.website">
                </div>
            </div>
        </div>

        <button type="submit"
                class="inline-flex items-center px-4 py-2 text-xs font-semibold tracking-widest text-white uppercase bg-gray-800 rounded-md border border-transparent ring-gray-300 transition duration-150 ease-in-out hover:bg-gray-700 active:bg-gray-900 focus:outline-none focus:border-gray-900 focus:ring disabled:opacity-25">
            Save
        </button>
    </form>
</template>

<script>
import useCompanies from '../../composables/companies'
import { onMounted } from 'vue';

export default {
    props: {
        id: {
            required: true,
            type: String
        }
    },

    setup(props) {
        const { errors, company, updateCompany, getCompany } = useCompanies()

        onMounted(getCompany(props.id))

        const saveCompany = async () => {
            await updateCompany(props.id)
        }

        return {
            errors,
            company,
            saveCompany
        }
    }
}
</script>

این بسیار شبیه به فرم ایجاد است ، اما در اینجا چند تفاوت وجود دارد.

اول ، ما قبول می کنیم لوازم و تعریف کنیم که ما انتظار داریم شناسه به عنوان مورد نیاز/رشته. سپس ، ما از داخل آن استفاده می کنیم راه اندازی (لوازم) و متدهای Composable را با آن پارامتر دقیق فراخوانی کنید: getCompany (props.id) و updateCompany (props.id)

بعد ، در فرم create ما یک a داشتیم فرم متغیری که به عنوان یک شی با کلیدها و مقادیر خالی تعریف کردیم. در این حالت ، ما در واقع یک متغیر داریم شرکت که در فایل Composable ذخیره می شود ، بنابراین نیازی نیست حتی آن را از جایی عبور دهیم ، فقط آن را از آن دریافت می کنیم استفاده از شرکتها () و از آن به عنوان محلی استفاده کنید. در همان رویداد نصب شده ، ما تماس می گیریم getCompany () اما نیازی نیست که نتیجه را به یک متغیر اختصاص دهیم ، همه اینها در کامپوزیت ها/شرکت ها. jsبه حالا ، زیبایی Composition API را می بینید؟

قسمتهای ارسال و اعتبارسنجی کاملاً مشابه فرم ایجاد هستند: در صورت موفقیت به فهرست هدایت می شود ، یا در صورت بروز خطای اعتبار خطا را نشان می دهد.


نتیجه

تمام ، ما یک CRUD با API Vue 3 Composition و Laravel API در پشت ساخته ایم.

البته ، این یک مثال بسیار ساده است: فقط با زمینه های متنی ، بدون عناصر یک ظاهر طراحی زیبا ، فقط با اصول اولیه. اما این دقیقاً نکته اصلی بود – برای شروع کار ، از اینجا می توانید در مورد Vue و API بیشتر بخوانید و سناریوهای پیچیده تری را تمرین کنید.

اگر چیزی را در این مقاله فراموش کرده ام/فراموش کرده ام ، یا اگر ایده ای برای مقالات بعدی در این زمینه دارید ، در نظرات به من اطلاع دهید.