Filament Radio 单选框组件完全指南:选项、描述、禁用与布尔模式的源码级解析
【免费下载链接】filamentA powerful open-source UI framework for Laravel • Build and ship apps & admin panels fast with Livewire项目地址: https://gitcode.com/GitHub_Trending/fi/filament
Filament 表单包(packages/forms)中的Radio组件用于渲染一组互斥的单选框(radio button group),供用户从预定义选项中选取唯一值。本文以官方文档 07-radio.md 为主线,结合 Radio.php 及其底层 Trait 与测试用例,系统讲解选项定义、选项描述、内联排列、按选项禁用、布尔快捷模式等全部能力,并深入其渲染与状态转换实现,帮助你在 Laravel + Livewire 的 Filament 表单中熟练驾驭该组件。
组件基础:定义选项并绑定状态
Radio组件通过make()指定状态字段名,再以options()方法传入一个「值 => 标签」的关联数组:
use Filament\Forms\Components\Radio; Radio::make('status') ->options([ 'draft' => 'Draft', 'scheduled' => 'Scheduled', 'published' => 'Published', ])options()不仅支持静态数组,也支持闭包动态计算,并可在闭包中注入表单字段相关的各种工具(Utility Injection,如当前$record、$state、$get、$livewire等)。
从源码看,options()定义于 Concerns/HasOptions.php,其底层签名接受array | Arrayable | string | Closure | null五种形态,并有两个值得注意的细节:
- 枚举类支持:若传入的字符串是 PHP 枚举类名,
options()会自动调用enum();而在getOptions()中(HasOptions.php),如果枚举实现了Filament\Support\Contracts\HasLabel接口,会用getLabel()作为标签,否则以枚举name作为标签。 - 标签支持嵌套数组:
options的类型注解为array<string | array<string>>,即每个选项的标签也可以是数组,从而支持分组渲染结构。
Radio在渲染时会为容器添加role="radiogroup"与aria-labelledby,保证无障碍语义(见 Radio.php 中的toEmbeddedHtml())。
为选项添加描述文字
当选项较多或含义需要补充说明时,可使用descriptions()为每个选项追加一段辅助描述文字:
use Filament\Forms\Components\Radio; Radio::make('status') ->options([ 'draft' => 'Draft', 'scheduled' => 'Scheduled', 'published' => 'Published', ]) ->descriptions([ 'draft' => 'Is not visible.', 'scheduled' => 'Will be visible.', 'published' => 'Is visible.', ])务必保证descriptions()数组的key与options()数组的key一一对应,描述才会正确匹配到对应选项。
descriptions()同样支持闭包动态计算。其实现位于 Concerns/HasDescriptions.php:
- 描述数组的类型为
array<string | Htmlable> | Arrayable | Closure,描述值可以是纯文本或Htmlable对象; - 结果会被缓存(
cachedDescriptions),同一生命周期内多次getDescriptions()不会重复求值; - 当未显式提供描述、但绑定了枚举且枚举实现了
Filament\Support\Contracts\HasDescription接口时,getDescriptions()会自动从枚举的getDescription()生成描述,实现「枚举即描述源」的约定。
测试 RadioTest.php 验证了getDescription('low')、hasDescription('missing')等检索行为。
内联排列选项
默认情况下各选项纵向堆叠显示。调用inline()可将选项横向排列成一行:
use Filament\Forms\Components\Radio; Radio::make('feedback') ->label('Like this post?') ->boolean() ->inline()也可以传入布尔值或闭包,动态控制是否内联:
Radio::make('feedback') ->label('Like this post?') ->boolean() ->inline(FeatureFlag::active())从源码看(Radio.php),inline()的完整签名为inline(bool | Closure $condition = true),内部保存到$isInline属性,isInline()会通过evaluate()求值闭包。渲染时:
- 非内联模式下,容器会应用网格布局(
grid($this->getColumns(), $gridDirection)),支持通过columns()控制每行选项数量; - 内联模式下为容器追加
fi-inlineCSS 类(见 Radio.php)。
测试 RadioTest.php 验证了默认isInline()为false、调用inline()后为true;L212-L225 进一步验证闭包内联与inline(false)撤销内联均可用。
禁用特定选项与校验联动
使用disableOptionWhen()禁用指定选项
disableOptionWhen()接受一个闭包,闭包内检查某个选项的$value是否需要被禁用:
use Filament\Forms\Components\Radio; Radio::make('status') ->options([ 'draft' => 'Draft', 'scheduled' => 'Scheduled', 'published' => 'Published', ]) ->disableOptionWhen(fn (string $value): bool => $value === 'published')闭包可注入两个参数:
| 参数 | 类型 | 说明 |
|---|---|---|
$value | mixed | 当前待判断选项的值 |
$label | string \| Illuminate\Contracts\Support\Htmlable | 当前待判断选项的标签 |
实现位于 Concerns/CanDisableOptions.php,其完整签名为disableOptionWhen(bool | Closure | null $callback, bool $merge = false):
- 默认(
$merge = false)会覆盖此前的禁用规则; - 传入
$merge = true时可追加多条禁用规则(isOptionDisabled[] = $callback); isOptionDisabled()逐条evaluate()所有规则,只要有一条命中即视为禁用。
渲染时(Radio.php)被禁用的选项会生成带disabled属性的原生input[type=radio]。
获取未禁用的选项做校验:getEnabledOptions()
禁用选项只影响交互,并不自动拦截提交的非法值。若要在校验层同步排除已禁用选项,可结合getEnabledOptions()与in()校验规则:
use Filament\Forms\Components\Radio; Radio::make('status') ->options([ 'draft' => 'Draft', 'scheduled' => 'Scheduled', 'published' => 'Published', ]) ->disableOptionWhen(fn (string $value): bool => $value === 'published') ->in(fn (Radio $component): array => array_keys($component->getEnabledOptions()))getEnabledOptions()(CanDisableOptions.php)会过滤掉所有被禁用规则命中的选项,返回[值 => 标签]数组;测试 RadioTest.php 验证了禁用archived后仅返回active与inactive。
实际上Radio组件对选项校验做了更强的自动化:默认状态无需显式调用in()。Radio重写了getInValidationRuleValues()(Radio.php),当没有手动指定校验值时,会自动以「未禁用选项的键集合」作为in校验白名单。测试 RadioTest.php 与 L272-L284 均验证:提交被禁用选项值会触发in校验错误,而提交合法值或空值(null)可通过校验。
布尔单选框:boolean()快捷模式
如果只是需要一个简单的「是/否」单选组,boolean()可以直接生成带 Yes / No 两个选项的单选框:
use Filament\Forms\Components\Radio; Radio::make('feedback') ->label('Like this post?') ->boolean()可通过命名参数自定义两个选项的标签:
Radio::make('feedback') ->label('Like this post?') ->boolean(trueLabel: 'Absolutely!') Radio::make('feedback') ->label('Like this post?') ->boolean(falseLabel: 'Not at all!')boolean()的实现非常巧妙(Radio.php):
- 自动把选项设为
[1 => trueLabel, 0 => falseLabel],默认文案取自语言包filament-forms::components.radio.boolean.true / false; - 同时注册一个
BooleanStateCast(isStoredAsInt => true)状态转换器,使得存储层使用整数1 / 0,而组件状态层暴露布尔值true / false。
配套的状态细节:
getDefaultState()(Radio.php)会把布尔型默认值统一转换为1 / 0(测试见 RadioTest.php);hasNullableBooleanState()恒返回true,表示该布尔状态允许为null(未选择);- 未显式设置状态转换器且未绑定枚举时,
getDefaultStateCasts()默认返回OptionStateCast(isNullable => true),即选项值可空(Radio.php); - 测试 RadioTest.php 验证了
fillForm(['is_active' => 1])后组件状态为true的整数与布尔双向转换。
渲染原理与无障碍
Radio实现了HasEmbeddedView,通过toEmbeddedHtml()(Radio.php)以内嵌视图方式输出 HTML,无需额外 Blade 模板文件。其渲染结构要点:
- 容器
div带role="radiogroup"、aria-labelledby,以及fi-fo-radio类(内联时追加fi-inline); - 每个选项是
<label>包裹的原生<input type="radio">,name统一使用字段 id,value为选项值; - 选项文本与描述(若存在)分别渲染为
.fi-fo-radio-label-text与.fi-fo-radio-label-description; - 字段整体禁用、单选项禁用、错误状态分别通过
disabled属性与fi-valid/fi-invalid类体现。
浏览器级渲染测试(RadioTest.php)会对/radio-test页面执行冒烟测试与无障碍检查(含暗色模式),并验证含双引号的选项值(如1/2" wrench)能被正确转义渲染。
完整示例:一个可运行的资源表单字段
将以上能力组合起来,即可得到一个功能完整的单选字段定义:
use Filament\Forms\Components\Radio; use Filament\Schemas\Schema; public function form(Schema $form): Schema { return $form ->schema([ Radio::make('status') ->label('Post status') ->options([ 'draft' => 'Draft', 'scheduled' => 'Scheduled', 'published' => 'Published', ]) ->descriptions([ 'draft' => 'Not visible to visitors.', 'scheduled' => 'Will become visible on the scheduled date.', 'published' => 'Immediately visible to visitors.', ]) ->default('draft') ->inline(), Radio::make('notify_subscribers') ->label('Notify subscribers?') ->boolean(trueLabel: 'Yes, notify them', falseLabel: 'No, keep it quiet'), ]) ->statePath('data'); }小结
Radio是 Filament 表单中最常用的单选输入组件之一,围绕它文档与源码共同构成了五个核心能力:静态/动态options()选项、descriptions()选项描述、inline()内联布局、disableOptionWhen()单选项禁用(配合自动化的getInValidationRuleValues()校验白名单),以及内置整数存储与布尔状态转换的boolean()快捷模式。结合 Radio.php 及其 Trait 与 RadioTest.php 中的测试断言,你可以放心地将其接入资源表单、弹窗表单或 Livewire 自定义表单,并获得完整的无障碍与校验保障。
如需了解更多校验规则(如in()的其它用法),可继续阅读 23-validation.md。
【免费下载链接】filamentA powerful open-source UI framework for Laravel • Build and ship apps & admin panels fast with Livewire项目地址: https://gitcode.com/GitHub_Trending/fi/filament
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考