基于Laravel+Vue+Inertia实现用户多角色多选功能(无第三方包)
Laravel + Vue + Inertia 实现用户多角色选择(无第三方包方案)
问题背景
我是Laravel新手,正在开发一个项目,需要实现多选功能让用户选择多个角色。数据库中users表与roles表为多对多关系,使用Laravel、VueJS和InertiaJS开发。已创建数据库表(users、roles、role_user)及对应模型,但不清楚如何将选中角色与数据库实体关联,以及如何为用户选择多角色,寻求不使用第三方包的实现方案。现有代码如下:
现有Create.vue代码
<script setup> import BreezeAuthenticatedLayout from '@/Layouts/Authenticated.vue'; import Button from '@/Components/Button.vue' import { Head } from '@inertiajs/inertia-vue3'; import { useForm, Link } from '@inertiajs/inertia-vue3'; import InputIconWrapper from '@/Components/InputIconWrapper.vue' import Input from '@/Components/Input.vue' import Label from '@/Components/Label.vue' import Multiselect from '@vueform/multiselect' defineProps({ errors: Object }) const data = useForm({ name: '', email: '', password: '', password_confirmation: '', }); const submit = ()=> { data.post("/users"); } </script> <form @submit.prevent="submit"> <div> <Label for="name" value="Name">Name</Label> <Input type="text" placeholder="Name" v-model="data.name" required autofocus autocomplete="name" class="block w-full w-full px-4 py-2 mt-2 mb-2 border rounded-md focus:outline-none focus:ring-1 focus:ring-blue-600" /> <div v-if="errors.name" class="text-red-500">{{ errors.name}}</div> </div> <div> <Label for="email" value="Email">Email</Label> <Input type="email" placeholder="Email" v-model="data.email" required autofocus autocomplete="email" class="block w-full w-full px-4 py-2 mt-2 mb-2 border rounded-md focus:outline-none focus:ring-1 focus:ring-blue-600" /> <div v-if="errors.email" class="text-red-500">{{ errors.email}}</div> </div> <div> <Label for="password" value="Password">Password</Label> <Input type="password" placeholder="Password" v-model="data.password" required autofocus autocomplete="password" class="block w-full w-full px-4 py-2 mt-2 mb-2 border rounded-md focus:outline-none focus:ring-1 focus:ring-blue-600" /> <div v-if="errors.password" class="text-red-500">{{ errors.password }}</div> </div> <div> <Label for="password_confirmation">Confirm Password</Label> <Input type="password" placeholder="Password" v-model="data.password_confirmation" class="block w-full w-full px-4 py-2 mt-2 mb-2 border rounded-md focus:outline-none focus:ring-1 focus:ring-blue-600" /> <div v-if="errors.password_confirmation" class="text-red-500">{{ errors.password_confirmation }}</div> </div> <div> <label for="role">Role</label> <multiselect v-model="selectedRoles" :options="roles" :multiple="true" placeholder="Select roles" ></multiselect> <div v-if="errors.password_confirmation" class="text-red-500">{{ errors.password_confirmation }}</div> </div> <div class="flex items-center mt-4"> <Button type="submit" variant="success" size="base" class="mr-2" > Add User </Button> <Button variant="danger" size="base" class="mr-2"><Link :href="route('users.index')" > Cancel</Link> </Button> </div> </form> <script> import axios from 'axios'; import Multiselect from '@vueform/multiselect'; export default { components: { Multiselect, }, data() { return { roles: [], selectedRoles: [], }; }, mounted() { this.fetchRoles(); }, methods: { fetchRoles() { axios.get('/api/roles') .then(response => { this.roles = response.data; }) .catch(error => { console.error(error); }); }, }, }; </script> <style src="@vueform/multiselect/themes/default.css"></style>
现有User Controller代码
public function create() { return inertia('Users/Create'); } public function store(StoreUserRequest $request) { $validatedData = $request->all(); $validatedData['password'] = Hash::make($validatedData['password']); User::create($validatedData); return Redirect::route('users.index') ->with('message', 'User created successfully'); }
解决方案步骤
1. 前端Vue组件调整
当前代码的核心问题是selectedRoles未与Inertia的表单数据绑定,导致提交时不会传递角色信息。以下提供两种实现方案:
方案1:修正现有第三方多选组件代码
<script setup> import BreezeAuthenticatedLayout from '@/Layouts/Authenticated.vue'; import Button from '@/Components/Button.vue' import { Head } from '@inertiajs/inertia-vue3'; import { useForm, Link } from '@inertiajs/inertia-vue3'; import Input from '@/Components/Input.vue' import Label from '@/Components/Label.vue' import Multiselect from '@vueform/multiselect' // 接收后端传递的角色列表 defineProps({ errors: Object, roles: Array }) // 将选中角色整合到表单数据中 const data = useForm({ name: '', email: '', password: '', password_confirmation: '', selectedRoles: [] }); const submit = ()=> { data.post("/users"); } </script> <template> <form @submit.prevent="submit"> <!-- 原有姓名、邮箱、密码字段保持不变 --> <div> <Label for="role" value="角色"></Label> <multiselect v-model="data.selectedRoles" :options="roles" :multiple="true" placeholder="选择角色" track-by="id" label="name" ></multiselect> <!-- 修正错误提示指向角色字段 --> <div v-if="errors.selectedRoles" class="text-red-500">{{ errors.selectedRoles}}</div> </div> <!-- 原有提交按钮部分保持不变 --> </form> </template> <style src="@vueform/multiselect/themes/default.css"></style>
方案2:无第三方包的原生多选实现
如果不想依赖第三方组件,直接用原生<select multiple>:
<!-- 替换第三方多选组件部分 --> <div> <Label for="roles" value="角色"></Label> <select v-model="data.selectedRoles" multiple class="block w-full px-4 py-2 mt-2 mb-2 border rounded-md focus:outline-none focus:ring-1 focus:ring-blue-600" > <option v-for="role in roles" :key="role.id" :value="role.id">{{ role.name }}</option> </select> <div v-if="errors.selectedRoles" class="text-red-500">{{ errors.selectedRoles}}</div> </div>
2. 后端控制器与验证调整
修改UserController
use App\Models\Role; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Redirect; public function create() { // 直接从后端传递角色列表给前端,避免额外请求 return inertia('Users/Create', [ 'roles' => Role::select('id', 'name')->get() ]); } public function store(StoreUserRequest $request) { $validatedData = $request->validated(); $validatedData['password'] = Hash::make($validatedData['password']); // 创建用户实例 $user = User::create($validatedData); // 关联选中的角色 if (!empty($request->selectedRoles)) { $user->roles()->attach($request->selectedRoles); } return Redirect::route('users.index') ->with('message', '用户创建成功'); }
添加请求验证规则
在app/Http/Requests/StoreUserRequest.php中补充角色字段的验证:
public function rules() { return [ 'name' => 'required|string|max:255', 'email' => 'required|string|email|max:255|unique:users', 'password' => 'required|string|confirmed|min:8', 'selectedRoles' => 'nullable|array', 'selectedRoles.*' => 'exists:roles,id' // 确保选中的角色ID在数据库中存在 ]; }
3. 确认模型多对多关联
确保User和Role模型已正确定义关联:
User.php
public function roles() { return $this->belongsToMany(Role::class); }
Role.php
public function users() { return $this->belongsToMany(User::class); }
内容的提问来源于stack exchange,提问作者Kim Chan
相关产品推荐
相关产品推荐

