Sử dụng song song Vue Router trong Laravel

Sử dụng song song Vue Router trong Laravel

Xin chào các bạn, trong bài viết này mình sẽ giới thiệu về cách sử dụng Vue Router trong dự án Laravel. Ở đây này mình sử dụng Vue 3 cùng Laravel 8, mọi người có thể tham khảo lại bài viết về cách tích hợp tại đây.

1. Cài đặt Vue Router

Đầu tiên chúng ta cài đặt Vue Router qua câu lệnh terminal sau.

npm install --save vue-router@next

Kiểm tra lại file package.json ta được như sau.

{
    "private": true,
    "scripts": {
        "dev": "npm run development",
        "development": "mix",
        "watch": "mix watch",
        "watch-poll": "mix watch -- --watch-options-poll=1000",
        "hot": "mix watch --hot",
        "prod": "npm run production",
        "production": "mix --production"
    },
    "devDependencies": {
        "axios": "^0.21",
        "laravel-mix": "^6.0.6",
        "lodash": "^4.17.19",
        "postcss": "^8.1.14",
        "vue-loader": "^16.8.3"
    },
    "dependencies": {
        "vue": "^3.2.23",
        "vue-router": "^4.0.12"
    }
}

2. Điều hướng lại web-pages routes của Laravel

Ở đây, mình dùng một file blade duy nhất để mount Vue App vào, và giao phó toàn bộ Vue Router để điều hướng web page. Laravel chỉ sử dụng các phần api routes để trả dữ liệu. Vì vậy mình sẽ chỉnh lại file routes\web.php của Laravel để điều hướng về một view duy nhất như sau.

<?php

use Illuminate\Support\Facades\Route;

Route::get('/{any}', function () {
    return view('welcome');
})->where('any', '^(?!api\/)[\/\w\.-]*');

3. Chuẩn bị bên Laravel

Chúng vào Laravel Tinker để fake dữ liệu bằng câu lệnh sau.

User::factory()->count(10)->create();

Sau đó tạo app\Http\Controllers\Api\UserController.php như sau

<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\User;

class UserController extends Controller
{
    public function index()
    {
        return response()->json(User::all(['id', 'name']));
    }

    public function show(User $user)
    {
        return response()->json($user);
    }
}

Tiếp theo khai báo API route trong file routes\web.php

<?php

use App\Http\Controllers\Api\UserController;
use Illuminate\Support\Facades\Route;

Route::apiResource('users', UserController::class)->only(['index', 'show']);

Ở trong file resources\views\welcome.blade.php ta sẽ cho Vue App mount vào như sau.

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Laravel</title>
</head>
<body>
    <div id="app"></div>
    <script src="{{ mix('js/app.js') }}"></script>
</body>
</html>

4. Chuẩn bị bên Vue

Trong file resources\js\app.js chúng ta sẽ khai báo import từ module vue-router phương thức createRouter để tạo router, và createWebHistory để sử dụng chế độ HTML5 history, như sau đây.

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

Để làm ví dụ, ta sẽ tạo ra 2 component resources\js\components\Index.vueresources\js\components\Show.vue theo thứ tự như dưới.
Trong file resources\js\components\Index.vue chúng sẽ sử dụng custom component <router-link> từ Vue Router để trỏ đến route có name là user.show và param là id của user từ dữ liệu API của Laravel trả về.

<template>
  <ul>
    <li v-for="user in users" :key="user.id">
      <router-link :to="{ name: 'users.show', params: { id: user.id } }">{{
        user.name
      }}</router-link>
    </li>
  </ul>
</template>

<script>
import { ref } from "vue";

export default {
  setup() {
    const users = ref([]);
    (async () => {
      const response = await axios.get("/api/users");
      users.value = response.data;
    })();

    return { users };
  },
};
</script>
<template>
  <ul>
    <li>Name: {{ user.name }}</li>
    <li>Email: {{ user.email }}</li>
  </ul>
</template>

<script>
import { reactive } from "vue";
import { useRoute } from "vue-router";

export default {
  setup() {
    const route = useRoute();
    const user = reactive({
      name: "",
      email: "",
    });
    (async () => {
      const response = await axios.get(`/api/users/${route.params.id}`);
      user.name = response.data.name;
      user.email = response.data.email;
    })();

    return { user };
  },
};
</script>

Khai báo import 2 component vừa tạo vào file  resources\js\app.js

import Index from './components/Index.vue';
import Show from './components/Show.vue';

Tiếp đó, ta tạo router với cấu hình các route định tuyến đến các components như sau.

const router = createRouter({
  history: createWebHistory(),
  routes: [
    { path: '/', name: 'users.index', component: Index },
    { path: '/:id', name: 'users.show', component: Show }
  ]
});

Ta sẽ tạo ra Vue App với template có chứa <router-view /> từ Vue Router để render ra component tương ứng với route đã chỉ định. Cùng với đó dùng chain method use để sử dụng biến router đã khai báo ở trên như sau.

createApp({ template: '<router-view />' }).use(router).mount('#app');

File resources\js\app.js của chúng ta tổng thể cuối cùng sẽ như sau.

require('./bootstrap');

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

import Index from './components/Index.vue';
import Show from './components/Show.vue';

const router = createRouter({
  history: createWebHistory(),
  routes: [
    { path: '/', name: 'users.index', component: Index },
    { path: '/:id', name: 'users.show', component: Show }
  ]
});

createApp({ template: '<router-view />' }).use(router).mount('#app');

5. Xem lại thành quả

Chúng ta chạy câu lệnh npm run dev để compile asset. Sau đó chạy php artisan serve và vào http://localhost:8000 để xem lại thành quả của mình.

Tài liệu tham khảo