Laravel 13 前端集成完全指南
Laravel 13 提供了现代化的前端集成方案,支持 Vite 构建工具,并与 Vue、React 等主流前端框架无缝集成。本文将深入探讨前端开发的最佳实践。
Vite 集成
安装与配置
1 2 3 4 5 6
| composer require laravel/breeze --dev php artisan breeze:install
npm install --save-dev vite laravel-vite-plugin
|
Vite 配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| import { defineConfig } from 'vite'; import laravel from 'laravel-vite-plugin'; import vue from '@vitejs/plugin-vue'; import react from '@vitejs/plugin-react';
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: { '@': '/resources/js', 'ziggy-js': '/vendor/tightenco/ziggy/dist/index.js', }, }, server: { hmr: { host: 'localhost', }, }, });
|
Blade 中使用 Vite
1 2 3 4 5 6 7 8 9 10 11 12
| <!DOCTYPE html> <html lang="{{ str_replace('_', '-', app()->getLocale()) }}"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> @vite(['resources/css/app.css', 'resources/js/app.js']) </head> <body> <div id="app"></div> </body> </html>
|
环境配置
1 2 3 4
| # .env VITE_APP_NAME="${APP_NAME}" VITE_API_URL="${APP_URL}/api" VITE_STRIPE_KEY="${STRIPE_KEY}"
|
1 2
| const appName = import.meta.env.VITE_APP_NAME; const apiUrl = import.meta.env.VITE_API_URL;
|
Vue.js 集成
安装 Vue
1 2
| npm install --save-dev vue @vitejs/plugin-vue npm install vue-router@4 pinia axios
|
Vue 应用入口
1 2 3 4 5 6 7 8 9 10 11
| import { createApp } from 'vue'; import { createPinia } from 'pinia'; import router from './router'; import App from './App.vue';
const app = createApp(App);
app.use(createPinia()); app.use(router);
app.mount('#app');
|
Vue Router 配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import { createRouter, createWebHistory } from 'vue-router'; import Home from '@/pages/Home.vue'; import Users from '@/pages/Users.vue';
const routes = [ { path: '/', name: 'home', component: Home }, { path: '/users', name: 'users', component: Users }, { path: '/users/:id', name: 'users.show', component: () => import('@/pages/UserShow.vue'), props: true, }, ];
export default createRouter({ history: createWebHistory(), routes, });
|
Pinia 状态管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import { defineStore } from 'pinia'; import { ref, computed } from 'vue';
export const useUserStore = defineStore('user', () => { const users = ref([]); const loading = ref(false);
const userCount = computed(() => users.value.length);
async function fetchUsers() { loading.value = true; try { const { data } = await axios.get('/api/users'); users.value = data; } finally { loading.value = false; } }
return { users, loading, userCount, fetchUsers }; });
|
Vue 组件示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| <template> <div class="user-list"> <div v-if="loading" class="loading">加载中...</div> <div v-else> <div v-for="user in users" :key="user.id" class="user-card"> <h3>{{ user.name }}</h3> <p>{{ user.email }}</p> <router-link :to="{ name: 'users.show', params: { id: user.id } }"> 查看详情 </router-link> </div> </div> </div> </template>
<script setup> import { onMounted } from 'vue'; import { storeToRefs } from 'pinia'; import { useUserStore } from '@/stores/user';
const userStore = useUserStore(); const { users, loading } = storeToRefs(userStore);
onMounted(() => { userStore.fetchUsers(); }); </script>
<style scoped> .user-card { border: 1px solid #ddd; padding: 1rem; margin-bottom: 1rem; } </style>
|
React 集成
安装 React
1 2
| npm install --save-dev react react-dom @vitejs/plugin-react npm install react-router-dom zustand axios
|
React 应用入口
1 2 3 4 5 6 7 8 9
| import { createRoot } from 'react-dom/client'; import { BrowserRouter } from 'react-router-dom'; import App from './App';
createRoot(document.getElementById('app')).render( <BrowserRouter> <App /> </BrowserRouter> );
|
React Router 配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import { Routes, Route } from 'react-router-dom'; import Home from './pages/Home'; import Users from './pages/Users'; import UserShow from './pages/UserShow';
export default function App() { return ( <Routes> <Route path="/" element={<Home />} /> <Route path="/users" element={<Users />} /> <Route path="/users/:id" element={<UserShow />} /> </Routes> ); }
|
Zustand 状态管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import { create } from 'zustand';
const useUserStore = create((set, get) => ({ users: [], loading: false,
fetchUsers: async () => { set({ loading: true }); try { const { data } = await axios.get('/api/users'); set({ users: data }); } finally { set({ loading: false }); } },
getUserById: (id) => { return get().users.find(user => user.id === parseInt(id)); }, }));
export default useUserStore;
|
React 组件示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| import { useEffect } from 'react'; import { Link } from 'react-router-dom'; import useUserStore from '../stores/user';
export default function Users() { const { users, loading, fetchUsers } = useUserStore();
useEffect(() => { fetchUsers(); }, []);
if (loading) { return <div>加载中...</div>; }
return ( <div className="user-list"> {users.map(user => ( <div key={user.id} className="user-card"> <h3>{user.name}</h3> <p>{user.email}</p> <Link to={`/users/${user.id}`}>查看详情</Link> </div> ))} </div> ); }
|
API 集成
Axios 配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| import axios from 'axios';
const api = axios.create({ baseURL: import.meta.env.VITE_API_URL, headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', }, });
api.interceptors.request.use(config => { const token = localStorage.getItem('token'); if (token) { config.headers.Authorization = `Bearer ${token}`; } const csrfToken = document.querySelector('meta[name="csrf-token"]')?.content; if (csrfToken) { config.headers['X-CSRF-TOKEN'] = csrfToken; } return config; });
api.interceptors.response.use( response => response, error => { if (error.response?.status === 401) { localStorage.removeItem('token'); window.location.href = '/login'; } return Promise.reject(error); } );
export default api;
|
API 服务封装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| export const userService = { async all() { const { data } = await api.get('/users'); return data; },
async find(id) { const { data } = await api.get(`/users/${id}`); return data; },
async create(payload) { const { data } = await api.post('/users', payload); return data; },
async update(id, payload) { const { data } = await api.put(`/users/${id}`, payload); return data; },
async delete(id) { await api.delete(`/users/${id}`); }, };
|
Ziggy 路由集成
安装 Ziggy
1 2
| composer require tightenco/ziggy npm install ziggy-js
|
配置 Ziggy
1 2 3 4 5 6 7 8
| return [ 'except' => [ 'debugbar.*', 'telescope.*', 'horizon.*', ], ];
|
Blade 中引入
1 2 3
| @routes {{-- 或指定路由组 --}} @routes('api')
|
前端使用
1 2 3 4 5 6 7
| import { route } from 'ziggy-js';
const url = route('users.show', { user: 1 }); const urlWithQuery = route('users.index', { page: 2, sort: 'name' });
const current = route().current(); const isActive = route().current('users.*');
|
Inertia.js 集成
安装 Inertia
1 2
| composer require inertiajs/inertia-laravel npm install @inertiajs/vue3
|
配置 Inertia
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| use Inertia\Inertia;
public function boot(): void { Inertia::share([ 'appName' => config('app.name'), 'auth' => fn() => [ 'user' => auth()->user(), ], 'flash' => fn() => [ 'success' => session('success'), 'error' => session('error'), ], ]); }
|
控制器返回
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| use Inertia\Inertia;
class UserController extends Controller { public function index() { return Inertia::render('Users/Index', [ 'users' => User::all(), 'filters' => request()->only(['search', 'role']), ]); }
public function store(Request $request) { User::create($request->validated());
return redirect()->route('users.index') ->with('success', '用户创建成功'); } }
|
Vue 页面组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <template> <Layout> <Head title="用户列表" /> <div class="mb-4"> <input v-model="form.search" placeholder="搜索用户..." /> </div>
<div v-for="user in users" :key="user.id"> {{ user.name }} </div>
<Link href="/users/create" class="btn">创建用户</Link> </Layout> </template>
<script setup> import { Link, Head } from '@inertiajs/vue3'; import Layout from '@/Layouts/Layout.vue'; import { useForm } from '@inertiajs/vue3';
const props = defineProps({ users: Array, filters: Object, });
const form = useForm({ search: props.filters.search || '', }); </script>
|
Livewire 集成
安装 Livewire
1
| composer require livewire/livewire
|
创建组件
1
| php artisan make:livewire UserList
|
Livewire 组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <?php
namespace App\Livewire;
use Livewire\Component; use App\Models\User;
class UserList extends Component { public $search = ''; public $role = '';
protected $queryString = ['search', 'role'];
public function render() { $users = User::query() ->when($this->search, fn($q) => $q->where('name', 'like', "%{$this->search}%")) ->when($this->role, fn($q) => $q->where('role', $this->role)) ->get();
return view('livewire.user-list', compact('users')); }
public function delete($id) { User::destroy($id); session()->flash('success', '用户已删除'); } }
|
Livewire 视图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <div> <input type="text" wire:model.live.debounce.300ms="search" placeholder="搜索..."> <select wire:model="role"> <option value="">所有角色</option> <option value="admin">管理员</option> <option value="user">用户</option> </select>
@if(session('success')) <div class="alert alert-success">{{ session('success') }}</div> @endif
<ul> @foreach($users as $user) <li> {{ $user->name }} <button wire:click="delete({{ $user->id }})" wire:confirm="确定删除?"> 删除 </button> </li> @endforeach </ul> </div>
|
Tailwind CSS 集成
安装 Tailwind
1 2
| npm install -D tailwindcss postcss autoprefixer npx tailwindcss init -p
|
Tailwind 配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| export default { content: [ './resources/**/*.blade.php', './resources/**/*.js', './resources/**/*.vue', ], theme: { extend: { colors: { primary: '#3490dc', }, }, }, plugins: [ require('@tailwindcss/forms'), require('@tailwindcss/typography'), ], };
|
CSS 入口文件
1 2 3 4 5 6 7 8 9 10 11 12 13
| @tailwind base; @tailwind components; @tailwind utilities;
@layer components { .btn { @apply px-4 py-2 rounded-lg font-semibold transition-colors; } .btn-primary { @apply btn bg-primary text-white hover:bg-primary-dark; } }
|
总结
Laravel 13 的前端集成提供了:
- 现代化的 Vite 构建工具
- Vue.js 和 React 的完整支持
- Inertia.js 单页应用方案
- Livewire 全栈组件方案
- Tailwind CSS 样式框架
- Ziggy 路由共享
选择适合项目需求的前端方案,可以大大提高开发效率。