Підручник з налаштування vue.js laravel

Laravel 11 і Vue.js — це чудове поєднання для написання чистого та ефективного коду.

У цьому посібнику ми разом побачимо, як створити сторінку з Vue.js у Laravel 11 за допомогою Laravel API.

Щоб протестувати Vue.js, ми створимо кінцеву точку API для отримання дописів і відображення їх у таблиці.

Приблизний час читання: 8 хвилин

Приклад, описаний у цій статті, доступний за адресою Github.

Щоб прочитати та повністю зрозуміти цю статтю, рекомендуємо прочитати статтю Laravel 11 і Vue.js: встановлення, налаштування та приклади, а реалізацію коду можна знайти за адресою Репозиторій GitHUB.

Database

Спочатку нам потрібно створити шаблон, міграцію, контролер і шлях API. Як і передбачалося в статті Laravel 11 і Vue.js: встановлення, налаштування та приклади давайте керувати сутністю даних пошта.

З цією командою Ремісник давайте створимо модель пошта і міграція:

php artisan make:model Post -m

Змінимо файл міграції база даних/migrations/xxxx_create_posts_table.php наступним чином:

public function up(): void
{
    Schema::create('posts', function (Blueprint $table) {
        $table->id();
        $table->string('title');
        $table->longText('content');
        $table->timestamps();
    });
}

Давайте відредагуємо модель app/Models/Post.php наступним чином:

class Post extends Model
{
    protected $fillable = [
        'title',
        'content',
    ];
}

Давайте створимо контролер PostController, і зокрема ми вказуємо на Folder Api

php artisan make:controller Api/PostController

Наразі в контролері ми лише повертатимемо колекцію всіх публікацій.

app/Http/Controllers/Api/PostController.php :

class PostController extends Controller
{
    public function index()
    {
        return Post::all();
    }
}

Давайте тепер визначимо їх Routes. Оскільки всі шляхи будуть для API, ми додамо їх до файлу routes/api.php. Таким чином Laravel автоматично додасть префікс api/ до маршрутів. Перед цим нам потрібно виконати команду Ремісник install:api підготувати заявку Laravel дляAPI.

php artisan install:api

Команда Ремісник як тільки його буде виконано, він змінить файл app.php присутні під каталогом завантажувач. Перевірте файл bootstrap/app.php:

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        api: __DIR__.'/../routes/api.php', 
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->statefulApi();
    })
    ->withExceptions(function (Exceptions $exceptions) {
        //
    })->create();

Тепер ми можемо додати маршрут дописів у файл routes/api.php, щоб навести наш приклад:

use App\Http\Controllers\Api\PostController;
 
Route::get('posts', [PostController::class, 'index']);

Виклик API від Vue

Тепер ми можемо додати код JS до компонента Vue PostsIndex які ми створили в статті Laravel 11 і Vue.js: встановлення, налаштування та приклади. Весь JS-код повинен бути розміщений у тегу <script>.

По-перше, нам потрібно додати змінну даних, якій будуть присвоєні всі публікації. Давайте назвемо цю змінну posts і ми призначаємо значення за замовчуванням порожній масив.

Відредагуйте файл ресурси/js/components/Posts/Index.vue:

<template>
    // ...
</template>
 
<script>
export default {
    data() {
        return {
            posts: []
        }
    }
}
</script>

Далі ми створимо метод fetchPosts хто зробить запит на придбання e /api/posts отримає всі дописи.

Коли запит успішний, метод .then буде виконано. Він додасть усі публікації з відповіді API до змінної даних posts.

Якщо щось піде не так, ми використовуємо .catch за будь-які помилки. Поки що ми обмежимося використанням файлу console.log.

Коли компоненти змонтовані (іншими словами, ініціалізовані), нам потрібно викликати fetchPosts(). Дзвінок буде зроблено в mounted. Ми використовуємо синтаксис this.fetchPosts(), насправді він походить від того самого компонента.

Файл ресурси/js/components/Posts/Index.vue стає:

<template>
    // ...
</template>
 
<script>
export default {
    data() {
        return {
            posts: []
        }
    },
    mounted() { 
        this.fetchPosts()
    },
    methods: {
        fetchPosts() {
            axios.get('/api/posts')
                .then(response => this.posts = response.data)
                .catch(error => console.log(error))
        }
    } 
}
</script>

Три спостереження:

  • Змінні ініціалізуються в data()
  • Ми додаємо спеціальні функції methods:
  • Якщо вам потрібно негайно викликати ці функції, вам потрібно викликати їх у mounted()

Тепер перейдіть на домашню сторінку та відкрийте Inspect вашого браузера. На вкладці Мережа ви побачите, що запит API зроблено /api/postsі показує всі дописи в частині відповіді.

ОТРИМАТИ laravel Vue api
ОТРИМАТИ Laravel Vue API

Перегляд даних API в таблиці

Тепер нам потрібно показати всі ці пости в таблиці. Для цього ми будемо використовувати директиву Vue v-for в елементі рядка tr таблиці.

Замінюємо статичні дані в таблиці на v-for="post in posts":

ресурси/js/components/Posts/Index.vue :

<template>
    <div class="overflow-hidden overflow-x-auto p-6 bg-white border-gray-200">
        <div class="min-w-full align-middle">
            <table class="min-w-full divide-y divide-gray-200 border">
                <thead>
                    <tr>
                        <th class="px-6 py-3 bg-gray-50 text-left">
                            <span class="text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">ID</span>
                        </th>
                        <th class="px-6 py-3 bg-gray-50 text-left">
                            <span class="text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">Title</span>
                        </th>
                        <th class="px-6 py-3 bg-gray-50 text-left">
                            <span class="text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">Content</span>
                        </th>
                        <th class="px-6 py-3 bg-gray-50 text-left">
                            <span class="text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">Created at</span>
                        </th>
                    </tr>
                </thead>
                <tbody class="bg-white divide-y divide-gray-200 divide-solid">
                    <tr v-for="post in posts"> 
                        <td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-900">
                            {{ post.id }}
                        </td>
                        <td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-900">
                            {{ post.title }}
                        </td>
                        <td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-900">
                            {{ post.content }}
                        </td>
                        <td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-900">
                            {{ post.created_at }}
                        </td>
                    </tr> 
                </tbody>
            </table>
        </div>
    </div>
</template>
 
<script>
// ...
</script>

Практично post in posts означає, що він приймає змінну posts на стороні компонента <script>і виконує цикл, призначаючи кожен елемент змінній post. Дорівнює foreach ($posts as $post) PHP.

Тепер, після оновлення сторінки в браузері, ви повинні побачити таблицю з усіма повідомленнями, отриманими з API.

таблиця з api laravel vue
Таблиці з Vue Laravel API

Vue.js Composition API 3

Vue.js версії 3 представив новий спосіб написання компонентів Vue під назвою API композиції. Починаючи з версії 3.2 Vue.js звільняється <script setup> як новий спосіб написання компонентів Vue.

Давайте тепер подивимося, як поєднати модульні компоненти <script setup> для написання багаторазового коду. Отже, давайте створимо складний компонент і викличемо його resources/js/composables/posts.js.

ресурси/js/composables/posts.js :

import { ref } from 'vue'
 
export default function usePosts() {
    const posts = ref([])
}

У цьому складному компоненті ми спочатку імпортуємо файл ref. Ref означає посилання, яке зробить змінні повідомлення адаптивними.

Отже, як і в будь-якому файлі, ми повинні експорт за замовчуванням . У нашому випадку ми будемо експортувати результат функції usePosts, це useXyz()це назва за замовчуванням, що починається з use.

Далі нам потрібно додати асинхронний метод для отримання публікацій.

ресурси/js/composables/posts.js :

import { ref } from 'vue'
 
export default function usePosts() {
    const posts = ref([])
 
    const getPosts = async () => { 
        axios.get('/api/posts')
            .then(response => {
                posts.value = response.data;
            })
    } 
    return { posts, getPosts } 
}

І всі викриті стани повинні бути повернуті. Тепер маємо postsgetPosts.

Тепер нам потрібно змінити компонент Vue. Замість <script> ми збираємося використовувати <script setup>.

ресурси/js/components/Posts/Index.vue :

<template>
    // ...
</template>
 
<script setup> 
import { onMounted } from "vue";
import usePosts from "../../composables/posts";
 
const { posts, getPosts } = usePosts()
onMounted(() => {
    getPosts()
})
</script>

Як бачите, таким чином нам доведеться писати менше коду в самому компоненті Vue, а все інше знаходиться в composable, який можна повторно використовувати в інших компонентах. Іншими словами, composable є еквівалентом класу Service in PHP/Laravel і компонент Vue використовувати метод Service, як контролер Laravel.

Використовуйте @ замість «../../»

Ми можемо покращити імпортування файлів замість повернення до каталогів із крапками на зразок ../../ ми можемо змінити це в знаку @. Для цього нам потрібно додати новий псевдонім до конфігурації life.

screw.config.js:

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue';
 
export default defineConfig({
    plugins: [
        laravel({
            input: [
                'resources/css/app.css',
                'resources/js/app.js',
            ],
            refresh: true,
        }),
        vue({
            template: {
                transformAssetUrls: {
                    base: null,
                    includeAbsolute: false,
                },
            },
        }),
    ],
    resolve: {
        alias: {
            vue: 'vue/dist/vue.esm-bundler.js',
            '@': '/resources/js', 
        },
    },
});

Тепер ми можемо імпортувати так:

ресурси/js/components/Posts/Index.vue:

import usePosts from "@/composables/posts"; 

Якщо імпортувати файли таким чином, ваша IDE може не вказувати на аномалію, попередження. Але ми можемо легко вирішити це, створивши файл jsconfig.json з кодом:

jsconfig.json:

{
    "compilerOptions": {
        "baseUrl": ".",
        "paths": {
            "@/*": ["resources/js/*"]
        }
    },
    "exclude": ["node_modules", "public"]
}

API ресурсів Eloquent для перетворення вмісту поля

Наразі наші дані в таблиці виглядають погано. Тому в цьому уроці ми використовуємо функцію Laravel під назвою Resources API для перетворення даних, наприклад:

  • зменшити деякі поля,
  • правильне форматування дати e
  • або ігнорувати деякі поля.

Спочатку створимо ресурс:

php artisan make:resource PostResource

Тому ми використовуємо Resource щоб переконатися в цьому PostController повернути всі дописи

app/Http/Controllers/Api/PostController.php :

class PostController extends Controller
{
    public function index()
    {
        return PostResource::collection(Post::all()); 
    }
}

Практично PostResource це обгортка перед запитом Eloquent, яка перетворює кожне поле на те, що ми хочемо.

За замовчуванням він нічого не перетворює, але ми можемо зробити це, надавши наш масив.

app/Http/Resources/PostResource.php :

class PostResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [ 
            'id' => $this->id,
            'title' => $this->title,
            'content' => substr($this->content, 0, 50) . '...',
            'created_at' => $this->created_at->toDateString()
        ]; 
    }
}

Ma Resource це не просто змінює поля contentcreated_at. Він також додає a data обгортка

Отже, на передній частині ми бачимо, що дані не відображаються.

laravel vue api порожня таблиця
laravel vue api порожня таблиця

Це пов'язано з data обгортка, додана ресурсом API. Нам просто потрібно додати ці дані в composable, де ми призначаємо дані відповіді змінній posts.

ресурси/js/composables/posts.js :

import { ref } from 'vue'
 
export default function usePosts() {
    const posts = ref([])
 
    const getPosts = async () => {
        axios.get('/api/posts')
            .then(response => {
                posts.value = response.data.data; 
            })
    }
 
    return { posts, getPosts }
}

Письмо .data.data це здається дивним, але це правильно: перше .data надходить із відповіді JS API за замовчуванням, а другий .data походить від оболонки ресурсу API Eloquent.

Тепер у нас знову є робоча таблиця зі зміненими значеннями. Вміст тепер має лише 50 символів і created_at це рядок, а не екземпляр Carbon.

laravel vue API з ресурсом
laravel vue API з ресурсом

Пагінація із зовнішнім пакетом Vue

Завантаження всього списку даних у таблицю може бути неоптимальним, особливо якщо є сотні чи тисячі записів. Ось тут і з’являється пагінація.

Ми додамо розмітку сторінок до таблиці публікацій за допомогою пакета laravel-vue-pagination .

Спочатку встановлюємо пакет.

npm install laravel-vue-pagination

Далі, замість того, щоб просто викликати всі публікації в контролері, нам потрібно розбити їх на сторінки.

app/Http/Controllers/Api/PostController.php :

class PostController extends Controller
{
    public function index()
    {
        return PostResource::collection(Post::paginate(10)); 
    }
}

Далі в компоненті Vue PostIndexв v-for, нам потрібно змінити post in posts.data.

ресурси/js/components/Posts/Index.vue:

<template>
// ...
<tr v-for="post in posts.data"> 
// ...
</template>

Отже, наша змінна posts у composable він має стати об’єктом замість масиву.

ресурси/js/composables/posts.js:

import { ref } from 'vue'
 
export default function usePosts() {
    const posts = ref({}) 
 
    const getPosts = async () => {
        axios.get('/api/posts')
            .then(response => {
                posts.value = response.data.data;
            })
    }
 
    return { posts, getPosts }
}

Далі нам потрібно встановити параметр сторінки getPosts. Також установіть цю сторінку як параметр URL-адреси. І вам не потрібно повертати результат даних. Ми повернемо повну відповідь API.

ресурси/js/composables/posts.js:

import { ref } from 'vue'
 
export default function usePosts() {
    const posts = ref({})
 
    const getPosts = async (page = 1) => { 
        axios.get('/api/posts?page=' + page) 
            .then(response => {
                posts.value = response.data; 
            })
    }
 
    return { posts, getPosts }
}

Тепер нам потрібно додати посилання на сторінки під таблицею.

Для цього нам також потрібно імпортувати пакет у компонент PostIndex Бачив.

Оскільки ми використовуємо Tailwind для дизайну ми імпортуємо версію Tailwind, але при необхідності є і версія Bootstrap. Або ви можете використовувати невідтворений макет і стилізувати його самостійно.

ресурси/js/components/Posts/Index.vue:

<template>
    <div class="overflow-hidden overflow-x-auto p-6 bg-white border-gray-200">
        <div class="min-w-full align-middle">
            <table class="min-w-full divide-y divide-gray-200 border">
                // ...
            </table>
 
            <TailwindPagination :data="posts" @pagination-change-page="getPosts" class="mt-4" /> 
        </div>
    </div>
</template>
 
<script setup>
import { onMounted } from "vue";
import { TailwindPagination } from 'laravel-vue-pagination'; 
import usePosts from "@/composables/posts";
 
const { posts, getPosts } = usePosts()
onMounted(() => {
    getPosts()
})
</script>

Зараз у нас є робочий макет.

Приклад, описаний у цій статті, доступний на Github.

розбиття сторінок laravel vue api
розбиття сторінок laravel vue api

Пов'язані читання

Ercole Palmeri

Авторе