
本文介绍如何在 laravel 中利用 php 8.1 枚举(enum)配合 inertia.js,将枚举的值、标签统一导出至 vue 组件,实现前后端状态定义的一致性与复用性,避免硬编码和重复维护。
本文介绍如何在 laravel 中利用 php 8.1 枚举(enum)配合 inertia.js,将枚举的值、标签统一导出至 vue 组件,实现前后端状态定义的一致性与复用性,避免硬编码和重复维护。
在现代 Laravel + Inertia + Vue 3 技术栈中,保持业务状态(如订单状态、用户角色、审核状态等)在 PHP 和前端之间的一致性至关重要。手动在 Vue 中重复定义 [{ value: 1, name: 'drafted' }, ...] 不仅冗余,还极易因两端不同步引发 bug。PHP 8.1 引入的原生枚举(Enums)为此提供了理想的数据源——只要通过 Inertia 中间件或页面响应将其结构化传递,即可在 Vue 中直接消费。
✅ 推荐实践:为 Enum 添加可序列化的选项能力
首先,为枚举注入标准化输出能力。我们不依赖魔法方法或反射,而是采用显式契约 + trait 复用的方式,确保类型安全与可维护性:
// app/Enums/Status.php
namespace App\Enums;
use App\Enums\Concerns\HasOptions;
enum Status: int
{
use HasOptions;
case DRAFTED = 1;
case SUBMITTED = 2;
case APPROVED = 3;
public function displayName(): string
{
return match ($this) {
self::DRAFTED => '草稿',
self::SUBMITTED => '已提交',
self::APPROVED => '已批准',
};
}
}
配套的 HasOptions trait 提供通用的 options() 方法,自动遍历所有枚举项并映射为前端友好的数组格式:
// app/Enums/Concerns/HasOptions.php
namespace App\Enums\Concerns;
use Illuminate\Support\Collection;
trait HasOptions
{
public static function options(): array
{
return collect(self::cases())
->map(fn ($case) => [
'value' => $case->value,
'label' => $case->displayName(),
'key' => $case->name, // 可选:用于调试或 i18n 键名
])
->toArray();
}
abstract public function displayName(): string;
}
? 提示:
displayName()返回中文(或国际化键),而非硬编码英文,便于后续接入vue-i18n;key字段保留枚举名称(如'DRAFTED'),方便前端做逻辑判断(如status.key === 'DRAFTED')。
? 两种传递方式:全局共享 or 按需注入
方式一:全局共享(适用于高频复用的枚举)
在 app/Http/Middleware/HandleInertiaRequests.php 的 share() 方法中注入:
use App\Enums\Status;
public function share(Request $request): array
{
return array_merge(parent::share($request), [
'statusOptions' => Status::options(),
// 可继续添加其他枚举:'roleOptions' => Role::options(),
]);
}
Vue 组件中通过 usePage() 直接获取:
<!-- resources/js/Pages/Post/Index.vue -->
<script setup>
import { usePage } from '@inertiajs/vue3'
const page = usePage()
const statusOptions = page.props.statusOptions
// → [{ value: 1, label: '草稿', key: 'DRAFTED' }, ...]
</script>
方式二:按需注入(推荐用于低频或上下文敏感枚举)
更轻量、更可控,避免污染全局 props:
// app/Http/Controllers/PostController.php
use App\Enums\Status;
public function create()
{
return Inertia::render('Post/Create', [
'statusOptions' => Status::options(),
]);
}
Vue 端使用 defineProps 解构(Composition API):
<script setup>
const props = defineProps({
statusOptions: {
type: Array,
required: true,
},
})
// 或解构写法:
// const { statusOptions } = defineProps(['statusOptions'])
</script>
⚠️ 注意事项与最佳实践
-
避免在 Enum 中耦合视图逻辑:
displayName()应返回语义化字符串(支持多语言键更好),而非 HTML 或样式类; -
慎用全局共享:仅对真正全站通用的枚举(如
Status,Priority)启用share();大量枚举全局注入会增大首屏 payload; -
类型安全增强(可选):配合 TypeScript,在 Vue 中定义
PropType类型,实现编译期校验; -
服务端验证联动:在表单提交时,后端应始终以
Status::from($request->status)校验并转换值,防止伪造数据; -
缓存优化:若枚举极少变动,可在
options()中加入static $cache或 Laravel 缓存层,避免每次请求重复计算。
通过这一模式,你获得的不仅是一组下拉选项,而是一个可维护、可测试、跨层一致的状态契约——PHP 枚举成为真实可信的单一数据源,Inertia 成为高效透明的桥梁,Vue 则专注渲染与交互。从此告别 ['draft' => 1, 'submitted' => 2] 的双写噩梦。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











