表单字段控件

开始

字段类(Field)位于 Filament\Form\Components 命名空间中。

字段组件和布局组件一起,在表单 schema 中。

如果你想在 Livewire 组件中使用这些字段,你可以将它们放到 getFormSchema() 方法中:

protected function getFormSchema(): array
{
return [
// ...
];
}

如果你在后台面板的资源或者关联管理器中使用,你必须将它们放在 $form->schema() 方法中:

public static function form(Form $form): Form
{
return $form
->schema([
// ...
]);
}

字段可以用静态方法 make() 传入字段名为参数创建。字段名应该对应 Livewire 组件的属性名。你可以使用Livewire"点语法"将字段绑定到像数组或者Eloquent模型这样的嵌套属性中。

use Filament\Forms\Components\TextInput;
 
TextInput::make('name')

设置标签

默认情况下,字段标签会按照字段名自动生成。你可以使用 label() 方法重写字段标签。如果你想使用语言本地化,可以使用这种方法自定义标签:

use Filament\Forms\Components\TextInput;
 
TextInput::make('name')->label(__('fields.name'))

此外,你也可以使用 translateLabel() 方法自动翻译标签:

use Filament\Forms\Components\TextInput;
 
TextInput::make('name')->translateLabel() // 相当于 `label(__('Name'))

设置ID

像设置标签一样,字段ID会根据他们的字段名自动生成。可以使用 id() 重写:

use Filament\Forms\Components\TextInput;
 
TextInput::make('name')->id('name-field')

验证属性

如果字段验证失败,错误消息中会引用标签名。可以使用 validationAttribute() 方法自定义错误消息使用的标签名:

use Filament\Forms\Components\TextInput;
 
TextInput::make('name')->validationAttribute('full name')

设置默认值

字段可以有默认值。如果表单 fill() 方法调用时没有传参,就会填充这个默认值。使用 default() 方法,可以定义默认值:

use Filament\Forms\Components\TextInput;
 
TextInput::make('name')->default('John')

帮助消息及提示

有时,你需要为表单用户提供额外消息。这种情况下,你可以使用帮助消息或者提示。

帮助消息显示在字段下面。helperText() 方法支持 Mardown 格式:

use Filament\Forms\Components\TextInput;
 
TextInput::make('name')->helperText('Your full name here, including any middle names.')

提示可以显示在标签旁边:

use Filament\Forms\Components\TextInput;
 
TextInput::make('password')->hint('[Forgotten your password?](forgotten-password)')

提示也可以添加图标,将其渲染在旁边:

use Filament\Forms\Components\RichEditor;
 
RichEditor::make('content')
->hint('Translatable')
->hintIcon('heroicon-s-translate')

自定义属性

可以在 extraAttributes() 中传入一个数组,自定义字段所在代码块的 HTML 属性:

use Filament\Forms\Components\TextInput;
 
TextInput::make('name')->extraAttributes(['title' => 'Text input'])

如果要将额外的HTML属性添加到输入框本身,则使用 extraInputAttributes():

use Filament\Forms\Components\TextInput;
 
TextInput::make('points')
->numeric()
->extraInputAttributes(['step' => '10'])

禁用

你可以禁用字段,使之不能编辑:

use Filament\Forms\Components\TextInput;
 
TextInput::make('name')->disabled()

另外,也可以传一个布尔值控制字段是否禁用:

use Filament\Forms\Components\Toggle;
 
Toggle::make('is_admin')->disabled(! auth()->user()->isAdmin())

请注意,禁用字段并不会影响保存,懂技术的用户仍然可以操作页面HTML改变他的值。

要阻止字段值被保存,请使用 dehydrated(false) 方法:

Toggle::make('is_admin')->dehydrated(false)

此外,你也可以根据情况决定是否保存一个字段,比如当用户是管理员时:

Toggle::make('is_admin')
->disabled(! auth()->user()->isAdmin())
->dehydrated(auth()->user()->isAdmin())

如果你使用后台面板,且只想在资源的新建页保存禁用字段:

use Filament\Resources\Pages\CreateRecord;
use Filament\Resources\Pages\Page;
 
TextInput::make('slug')
->disabled()
->dehydrated(fn (Page $livewire) => $livewire instanceof CreateRecord)

自动聚焦

大部分字段时可自动聚焦的。一般来说,让你表单中第一个重要的字段获得自动聚焦,会带来最好的用户体验。

use Filament\Forms\Components\TextInput;
 
TextInput::make('name')->autofocus()

设置占位符

很多字段当值为空时,通常会有一个占位符。你可以使用 placeholder() 方法自定义:

use Filament\Forms\Components\TextInput;
 
TextInput::make('name')->placeholder('John Doe')

全局设置

如果你想要全局修改字段的默认行为,你可以在服务提供者的 boot() 方法中调用静态方法 configrueUsing(),传入闭包修改其使用的组件。比如,你想让所有的复选框inline(false),你可以这样做:

use Filament\Forms\Components\Checkbox;
 
Checkbox::configureUsing(function (Checkbox $checkbox): void {
$checkbox->inline(false);
});

当然,你仍然可以对每个字段单独重写这一样式:

use Filament\Forms\Components\Checkbox;
 
Checkbox::make('is_admin')->inline()

文本框

文本框(Text Input) 用于与字符串交互:

use Filament\Forms\Components\TextInput;
 
TextInput::make('name')

你可以用一系列方法设置文本框类型。其中有些,比如像 email(),同时也提供验证:

use Filament\Forms\Components\TextInput;
 
TextInput::make('text')
->email()
->numeric()
->password()
->tel()
->url()

同样的,你也可以使用 type() 传一个HTML 文本框类型参数:

use Filament\Forms\Components\TextInput;
 
TextInput::make('backgroundColor')->type('color')

你也可以使用 prefix()suffix() 方法,在文本框前后添加文本内容:

use Filament\Forms\Components\TextInput;
 
TextInput::make('domain')
->url()
->prefix('https://')
->suffix('.com')

你可以使用 prefixIcon()suffixIcon() 方法在输入框前后放入图标:

use Filament\Forms\Components\TextInput;
 
TextInput::make('domain')
->url()
->prefixIcon('heroicon-o-external-link')
->suffixIcon('heroicon-o-external-link')

你可以设置 minLength()maxLength() 限制输入文本长度。此方法会同时添加前端和后端验证:

use Filament\Forms\Components\TextInput;
 
TextInput::make('name')
->minLength(2)
->maxLength(255)

你也可以通过设置 length() 指定输入框的精确长度。此方法同样在前后端都添加了验证:

use Filament\Forms\Components\TextInput;
 
TextInput::make('code')->length(8)

另外,你也可以设置 minValue()maxValue() 验证输入的最小和最大值:

use Filament\Forms\Components\TextInput;
 
TextInput::make('number')
->numeric()
->minValue(1)
->maxValue(100)

你可以使用 autocomplete() 方法,为文本输入框设置自动补全配置:

use Filament\Forms\Components\TextInput;
 
TextInput::make('password')
->password()
->autocomplete('new-password')

你也可以用 disableAutocomplete(),它是关闭自动补全的快捷方法:

use Filament\Forms\Components\TextInput;
 
TextInput::make('password')
->password()
->disableAutocomplete()

更多自动补全选项,文本框也支持 datalists

输入遮罩

输入遮罩(Input mask)定义了输入必须遵循的格式。

Filament 中,你可以在 mask() 方法中与 Mask 对象进行交互,配置你的mask:

use Filament\Forms\Components\TextInput;
 
TextInput::make('name')
->mask(fn (TextInput\Mask $mask) => $mask->pattern('+{7}(000)000-00-00'))

在底层,masking 使用 imaskjs 驱动。它主要的特性在Filament中同样可用。先阅读指南,再使用 Filament 实现,或许是最便利的方法。

你可以定义和配置一个 numeric mask,用来处理数字:

use Filament\Forms\Components\TextInput;
 
TextInput::make('number')
->numeric()
->mask(fn (TextInput\Mask $mask) => $mask
->numeric()
->decimalPlaces(2) // Set the number of digits after the decimal point.
->decimalSeparator(',') // Add a separator for decimal numbers.
->integer() // Disallow decimal numbers.
->mapToDecimalSeparator([',']) // Map additional characters to the decimal separator.
->minValue(1) // Set the minimum value that the number can be.
->maxValue(100) // Set the maximum value that the number can be.
->normalizeZeros() // Append or remove zeros at the end of the number.
->padFractionalZeros() // Pad zeros at the end of the number to always maintain the maximum number of decimal places.
->thousandsSeparator(','), // Add a separator for thousands.
)

Enum masks 限制了用户的输入选项:

use Filament\Forms\Components\TextInput;
 
TextInput::make('code')->mask(fn (TextInput\Mask $mask) => $mask->enum(['F1', 'G2', 'H3']))

Range masks 可被用作限制数字输入范围:

use Filament\Forms\Components\TextInput;
 
TextInput::make('code')->mask(fn (TextInput\Mask $mask) => $mask
->range()
->from(1) // Set the lower limit.
->to(100) // Set the upper limit.
->maxValue(100), // Pad zeros at the start of smaller numbers.
)

除了简单样式,你也可以定义多重模式块pattern blocks:

use Filament\Forms\Components\TextInput;
 
TextInput::make('cost')->mask(fn (TextInput\Mask $mask) => $mask
->patternBlocks([
'money' => fn (Mask $mask) => $mask
->numeric()
->thousandsSeparator(',')
->decimalSeparator('.'),
])
->pattern('$money'),
)

里面也包含了一个 money() 方法,可以更容易格式化货币输入。本例,前缀符号是 $、千位分隔符 , 、及两位小数:

use Filament\Forms\Components\TextInput;
 
TextInput::make('cost')->mask(fn (TextInput\Mask $mask) => $mask->money('$', ',', 2))

Datalists

你可以使用 datalist() 方法为文本框指定一个 datalist选项:

TextInput::make('manufacturer')
->datalist([
'BWM',
'Ford',
'Mercedes-Benz',
'Porsche',
'Toyota',
'Tesla',
'Volkswagen',
])

Datalist 为用户提供文本框自动补全选项。不过,这些值只是单纯推荐,用户仍然可以输入任何值到文本框中。如果你想要限制定义选项,请用选择框

下拉列表

下拉列表组件让你可以使用一组预定义的选项:

use Filament\Forms\Components\Select;
 
Select::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])

你可以使用 searchable() 方法启用搜索输入框,使之更容易找到选项:

use App\Models\User;
use Filament\Forms\Components\Select;
 
Select::make('authorId')
->label('Author')
->options(User::all()->pluck('name', 'id'))
->searchable()

如果你有很多选项,需要根据数据库搜索或者其他外部数据源填充数据,你可以使用 getSearchResultsUsing()getOptionLabelUsing() 方法代替 options()

getSearchResultsUsing() 方法接收一个回调函数作为参数,该回调以 $key => $value 格式返回搜索结果。

getSearchResultsUsing() 方法接收一个回调函数,该回调将选中的选项的 $value 转换成标签。

Select::make('authorId')
->searchable()
->getSearchResultsUsing(fn (string $searchQuery) => User::where('name', 'like', "%{$searchQuery}%")->limit(50)->pluck('name', 'id'))
->getOptionLabelUsing(fn ($value): ?string => User::find($value)?->name),

使用 disablePlaceholderSelection() 方法可以防止占位符被选中:

use Filament\Forms\Components\Select;
 
Select::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])
->default('draft')
->disablePlaceholderSelection()

依赖下拉列表

通常情况下,你可能会需要用到"依赖"下拉列表,它基于其他字段控件的状态值填充选项。

高级表单区域提及的一些技术,需要使用依赖下拉列表。可使用这些技术对所有表单组件进行动态自定义。

BelongsTo关联中自动添加数据

你可以使用BelongsToSelectrelationship() 方法,用以从配置的关联模型中自动检索和保存选项:

use Filament\Forms\Components\BelongsToSelect;
 
BelongsToSelect::make('authorId')
->relationship('author', 'name')

要启用这个功能,你必须按照关联字段区域的指南进行设置。如果你使用了后台面板,可以跳过此步。

你可以使用 relationship() 方法的第三个参数,自定义数据库查询:

use Filament\Forms\Components\BelongsToSelect;
use Illuminate\Database\Eloquent\Builder;
 
BelongsToSelect::make('authorId')
->relationship('author', 'name', fn (Builder $query) => $query->withTrashed())

如果你想要自定义每个选项的标签,比如让其更具描述性、或者连接名和姓,你应该在数据库迁移中使用(virtual)虚拟字段:

$table->string('full_name')->virtualAs('concat(first_name, \' \', last_name)');
use Filament\Forms\Components\BelongsToSelect;
 
BelongsToSelect::make('authorId')
->relationship('author', 'full_name')

另外,你也可以使用 getOptionLabelUsing() 方法将选中选项的Eloquent模型转换成标签。不过需要注意的是,这种方式比使用虚拟字段(virtual column)低效:

use Filament\Forms\Components\BelongsToSelect;
use Illuminate\Database\Eloquent\Model;
 
BelongsToSelect::make('authorId')
->relationship('author', 'first_name')
->getOptionLabelFromRecordUsing(fn (Model $record) => "{$record->first_name} {$record->last_name}")

创建新记录

你可以自定义表单,使之可以用来创建新纪录并附加到 BelongsTo 关联:

use Filament\Forms\Components\BelongsToSelect;
use Illuminate\Database\Eloquent\Model;
 
BelongsToSelect::make('authorId')
->relationship('author', 'name')
->createOptionForm([
Forms\Components\TextInput::make('name')
->required(),
Forms\Components\TextInput::make('email')
->required()
->email(),
]),

这个表单会在模态框内打开,用户可以在里面填写数据。一旦表单提交,新记录就会被字段选中。

由于HTML不支持嵌套 <form> 元素,你必须在视图的 <form> 表单之外渲染模态框。如果你使用后台面板,这已经被包含在内了:

<form wire:submit.prevent="submit">
{{ $this->form }}
 
<button type="submit">
Submit
</button>
</form>
 
{{ $this->modal }}

多选下拉列表

多选下拉列表允许你从一组预定义的选项里选择多个值:

use Filament\Forms\Components\MultiSelect;
use Filament\Forms\Components\Select;
 
MultiSelect::make('technologies')
->options([
'tailwind' => 'TailwindCSS',
'alpine' => 'Alpine.js',
'laravel' => 'Laravel',
'livewire' => 'Laravel Livewire',
])

这些选项以 JSON 格式返回。如果你使用Eloquent保存,你应该添加 array cast到模型属性:

use Illuminate\Database\Eloquent\Model;
 
class App extends Model
{
protected $casts = [
'technologies' => 'array',
];
 
// ...
}

如果你有很多选项,希望可以基于数据库搜索或者其他数据源添加数据,你可以使用 getSearchResultsUsing()getOptionLabelsUsing() 方法代替 options()getSearchResultsUsing() 方法接收一个以 $key => $value 格式返回搜索结果为参数的回调函数。

getSearchResultsUsing() 方法接收一个将选中的选项的 $value 转换成标签的回调函数。

use Filament\Forms\Components\MultiSelect;
 
MultiSelect::make('technologies')
->getSearchResultsUsing(fn (string $searchQuery) => Technology::where('name', 'like', "%{$searchQuery}%")->limit(50)->pluck('name', 'id'))
->getOptionLabelsUsing(fn (array $values) => Technology::find($values)->pluck('name')),

自动从 BelongsToMany 关联中填充数据

你可以使用 BelongsToManyMultiSelectrelationship() 方法,配置的关联模型用来自动检索和保存选项:

use App\Models\App;
use Filament\Forms\Components\BelongsToManyMultiSelect;
 
BelongsToManyMultiSelect::make('technologies')
->relationship('technologies', 'name')

要启用这个功能,你必须按照关联字段的指示。如果你使用了[后台面板],可以跳过此步。

你可以使用 relationship() 方法的第三个参数,自定义数据库查询:

use Filament\Forms\Components\BelongsToManyMultiSelect;
use Illuminate\Database\Eloquent\Builder;
 
BelongsToManyMultiSelect::make('technologies')
->relationship('technologies', 'name', fn (Builder $query) => $query->withTrashed())

如果你想要自定义每个选项的标签,比如使之更具描述性、或者连接名和姓,你应该在数据库迁移中使用(virtual)虚拟字段:

$table->string('full_name')->virtualAs('concat(first_name, \' \', last_name)');
use Filament\Forms\Components\BelongsToManyMultiSelect;
 
BelongsToManyMultiSelect::make('participants')
->relationship('participants', 'full_name')

此外,你也可以使用 getOptionLabelUsing() 方法将选中选项的Eloquent模型转换成标签。不过需要注意的是,这种方式会比使用虚拟字段(virtual column)性能低:

use Filament\Forms\Components\BelongsToManyMultiSelect;
use Illuminate\Database\Eloquent\Model;
 
BelongsToManyMultiSelect::make('participants')
->relationship('participants', 'first_name')
->getOptionLabelFromRecordUsing(fn (Model $record) => "{$record->first_name} {$record->last_name}")

复选框

复选框(checkbox)组件,类似于toggle,让你可以和布尔值交互。

use Filament\Forms\Components\Checkbox;
 
Checkbox::make('is_admin')

复选框字段有两种布局模式,inline 和 stacked。默认为inline。

如果是inline,标签会紧邻着复选框:

use Filament\Forms\Components\Checkbox;
 
Checkbox::make('is_admin')->inline()

如果是stacked,标签会在复选框之上:

use Filament\Forms\Components\Checkbox;
 
Checkbox::make('is_admin')->inline(false)

如果你使用 Eloquent 保存布尔值,你应该添加 boolean cast 到模型属性中:

use Illuminate\Database\Eloquent\Model;
 
class User extends Model
{
protected $casts = [
'is_admin' => 'boolean',
];
 
// ...
}

Toggle

Toggle 组件,类似于 复选框,用于和布尔值交互。

use Filament\Forms\Components\Toggle;
 
Toggle::make('is_admin')

Toggle 字段控件有两种布局模式,inline 和 stacked。默认是inline(行内)。

如果是inline,标签会紧挨着它:

use Filament\Forms\Components\Toggle;
 
Toggle::make('is_admin')->inline()

如果是stacked,标签会在它上面:

use Filament\Forms\Components\Toggle;
 
Toggle::make('is_admin')->inline(false)

Toggle 也可以使用开/关图标。会被显示在手柄上,指示字段含义。参数必须是Blade模板图标组件:

use Filament\Forms\Components\Toggle;
 
Toggle::make('is_admin')
->onIcon('heroicon-s-lightning-bolt')
->offIcon('heroicon-s-user')

你也可以自定义每个状态显示的颜色。可用颜色包括 primarysecondarysuccesswarningdanger

use Filament\Forms\Components\Toggle;
Toggle::make('is_admin')
->onColor('success')
->offColor('danger')

如果你使用 Eloquent 保存布尔值,你应该添加 boolean cast到相应的模型属性上。

use Illuminate\Database\Eloquent\Model;
 
class User extends Model
{
protected $casts = [
'is_admin' => 'boolean',
];
 
// ...
}

复选框列表

复选框列表让你可以从一组预定义的选项中选择多个值:

use Filament\Forms\Components\CheckboxList;
 
CheckboxList::make('technologies')
->options([
'tailwind' => 'TailwindCSS',
'alpine' => 'Alpine.js',
'laravel' => 'Laravel',
'livewire' => 'Laravel Livewire',
])

这些选项以 JSON 格式返回。如果你使用 Eloquent 保存数据,你应该添加array cast到模型属性中:

use Illuminate\Database\Eloquent\Model;
 
class App extends Model
{
protected $casts = [
'technologies' => 'array',
];
 
// ...
}

你也可以使用 columns() 方法将选项分成对应的列数:

use Filament\Forms\Components\CheckboxList;
 
CheckboxList::make('technologies')
->options([
'tailwind' => 'TailwindCSS',
'alpine' => 'Alpine.js',
'laravel' => 'Laravel',
'livewire' => 'Laravel Livewire',
])
->columns(2)

此方法像gridcolumns() 方法一样,接收选项作为参数。你可以在不同的临界点中,以自适应的方式定制列数。

自动从BelongsToMany关联中获取数据

你可以使用 BelongsToManyCheckboxListrelationship() 方法,配置的关联模型用来自动检索和保存选项:

use App\Models\App;
use Filament\Forms\Components\BelongsToManyCheckboxList;
 
BelongsToManyCheckboxList::make('technologies')
->relationship('technologies', 'name')

要启用这个功能,你必须按照关联字段区域的指南进行设置。如果你使用了后台面板,可以跳过此步。

你可以使用 relationship() 方法的第三个参数,自定义数据库查询:

use Filament\Forms\Components\BelongsToManyCheckboxList;
use Illuminate\Database\Eloquent\Builder;
 
BelongsToManyCheckboxList::make('technologies')
->relationship('technologies', 'name', fn (Builder $query) => $query->withTrashed())

如果你想要自定义每个选项的标签,比如让它更具描述性、或者连接名和姓,你应该在数据库迁移中使用(virtual)虚拟字段:

$table->string('full_name')->virtualAs('concat(first_name, \' \', last_name)');
use Filament\Forms\Components\BelongsToManyCheckboxList;
 
BelongsToManyCheckboxList::make('participants')
->relationship('participants', 'full_name')

另外,你也可以使用 getOptionLabelUsing() 方法将选中选项的Eloquent模型转换成标签。不过需要注意的是,这种方式会比使用虚拟字段(virtual column)性能低:

use Filament\Forms\Components\BelongsToManyCheckboxList;
use Illuminate\Database\Eloquent\Model;
 
BelongsToManyCheckboxList::make('participants')
->relationship('participants', 'first_name')
->getOptionLabelFromRecordUsing(fn (Model $record) => "{$record->first_name} {$record->last_name}")

单选框

单选框提供单选按钮组,用来从一个预定义的选项列表中选择一个值:

use Filament\Forms\Components\Radio;
 
Radio::make('status')
->options([
'draft' => 'Draft',
'scheduled' => 'Scheduled',
'published' => 'Published'
])

你可以使用 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.'
])

请确保在描述数组中使用和选项数组中同样的 键(key),这样描述才能和选项匹配。

如果你只是需要简单的布尔单选按钮组,带有"是/否"选项,你可以使用 boolean() 方法:

Radio::make('feedback')
->label('Do you like this post?')
->boolean()

你可以使用标签在行内(inline)显示选项:

Radio::make('feedback')
->label('Do you like this post?')
->boolean()
->inline()

日期时间选择器

日期时间选择器(Date-time Picker)提供了选择日期和时间的交互接口。

use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\DateTimePicker;
use Filament\Forms\Components\TimePicker;
 
DateTimePicker::make('published_at')
DatePicker::make('date_of_birth')
TimePicker::make('alarm_at')

你可以限制选择器可选的最小/最大日期。minDate()maxDate() 方法接收一个 DateTime 实例(如 Carbon)或字符串作为参数:

use Filament\Forms\Components\DatePicker;
 
DatePicker::make('date_of_birth')
->minDate(now()->subYears(150))
->maxDate(now())

你可以使用 format()方法,自定义存入数据库时的字段格式。它接收字符串日期格式,使用PHP日期格式

use Filament\Forms\Components\DatePicker;
 
DatePicker::make('date_of_birth')->format('d/m/Y')

你可以自定义字段的显示格式,以不同于存入数据库时候的格式。对此,使用 displayFormat() 方法,它也可以接收字符串日期格式,使用PHP date formatting tokens:

use Filament\Forms\Components\DatePicker;
 
DatePicker::make('date_of_birth')->displayFormat('d/m/Y')

当使用的是时间选择器时,你可以使用 withoutSeconds() 方法禁用秒输入框:

use Filament\Forms\Components\DateTimePicker;
 
DateTimePicker::make('published_at')->withoutSeconds()

在某些国家,星期的第一天不是周一。使用 forms.components.date_time_picker.first_day_of_week 配置选项或者组件的 firstDayOfWeek() 方法,可以自定义时间选择器中星期的第一天。可接收的参数值从 0 到 7,周一是1,周日为 7 或 0:

use Filament\Forms\Components\DateTimePicker;
 
DateTimePicker::make('published_at')->firstDayOfWeek(7)

另外也有一些额外的便利方法,可以更方便地设置星期的第一天:

use Filament\Forms\Components\DateTimePicker;
 
DateTimePicker::make('published_at')->weekStartsOnMonday()
DateTimePicker::make('published_at')->weekStartsOnSunday()

时区

你可以使用 timezone() 方法,让用户可以管理自己的时区:

use Filament\Forms\Components\DateTimePicker;
 
DateTimePicker::make('published_at')->timezone('America/New_York')

日期仍然会使用应用配置的时区保存,日期在加载时会适用新的时区,表单保存时会转换回系统配置的时区。

文件上传

文件上传字段基于 Filepond

use Filament\Forms\Components\FileUpload;
 
FileUpload::make('attachment')

默认情况下,文件会被公开上传到默认的存储盘中。

可以使用 disk()directory()visibility() 方法,修改文件保存的磁盘和目录,以及可见性:

use Filament\Forms\Components\FileUpload;
 
FileUpload::make('attachment')
->disk('s3')
->directory('form-attachments')
->visibility('private')

请注意,由开发者决定是否将文件从磁盘上删除,因为Filament不知道其他地方是否也依赖于他。一种自动实现的方法是监听模型事件

默认情况下,新上传的文件会生成随机文件名。可以使用 preserveFilenames() 方法,保留上传文件的原文件名:

use Filament\Forms\Components\FileUpload;
 
FileUpload::make('attachment')->preserveFilenames()

你可以使用 getUploadedFileNameForStorageUsing() 方法,在回调函数中返回字符串,这样就可以完全自定义文件名怎么生成:

use Livewire\TemporaryUploadedFile;
 
FileUpload::make('attachment')
->getUploadedFileNameForStorageUsing(function (TemporaryUploadedFile $file): string {
return (string) str($file->getClientOriginalName())->prepend('custom-prefix-');
})

使用 storeFileNamesIn() 方法,你可以在保留原始文件名的同时,使用随机生成的文件名:

use Filament\Forms\Components\FileUpload;
 
FileUpload::make('attachments')
->multiple()
->storeFileNamesIn('attachment_file_names')

attachment_file_names 中会保存你上传文件的原始文件名。

你可以使用 acceptedFileTypes() 方法,传入MIME类型数组,来限制可以上传的文件类型。你也可以使用 image() 方法作为速记方法,允许所有图片的MIME类型。

use Filament\Forms\Components\FileUpload;
 
FileUpload::make('document')->acceptedFileTypes(['application/pdf'])
FileUpload::make('image')->image()

你也可以限制上传文件的大小,以 KB 计算:

use Filament\Forms\Components\FileUpload;
 
FileUpload::make('attachment')
->minSize(512)
->maxSize(1024)

要自定义 Livewire 默认的文件上传验证规则,请查阅相关文档

Filepone 允许你在上传之前对图片进行裁切或者调整大小。你可以使用 imageCropAspectRatio()imageResizeTargetHeight()imageResizeTargetWidth() 方法进行自定义。

use Filament\Forms\Components\FileUpload;
 
FileUpload::make('image')
->image()
->imageCropAspectRatio('16:9')
->imageResizeTargetWidth('1920')
->imageResizeTargetHeight('1080')

你也可以修改Filepone组件的一般外观。这些方法可用的选项可以在Filepond网站查看。

use Filament\Forms\Components\FileUpload;
 
FileUpload::make('attachment')
->imagePreviewHeight('250')
->loadingIndicatorPosition('left')
->panelAspectRatio('2:1')
->panelLayout('integrated')
->removeUploadedFileButtonPosition('right')
->uploadButtonPosition('left')
->uploadProgressIndicatorPosition('left')

你也可以上传多个文件。网址会以 JSON 方式保存:

use Filament\Forms\Components\FileUpload;
 
FileUpload::make('attachments')->multiple()

如果你使用Eloquent保存这些网址,你需要添加 array cast到模型属性中:

use Illuminate\Database\Eloquent\Model;
 
class Message extends Model
{
protected $casts = [
'attachments' => 'array',
];
 
// ...
}

使用 minFiles()maxFiles() 方法,你可以自定义文件上传的数量:

use Filament\Forms\Components\FileUpload;
 
FileUpload::make('attachments')
->multiple()
->minFiles(2)
->maxFiles(5)

使用 enableReordering() 方法,你也可以启用上传文件的重新排序功能:

use Filament\Forms\Components\FileUpload;
 
FileUpload::make('attachments')
->multipe()
->enableReordering()

使用 enableOpen() 方法,你可以添加按钮使文件可以在新的标签页中打开:

use Filament\Forms\Components\FileUpload;
 
FileUpload::make('attachments')
->multipe()
->enableOpen()

使用 enableDownload() 方法,你可以为每个上传文件添加一个下载按钮:

use Filament\Forms\Components\FileUpload;
FileUpload::make('attachments')
->multipe()
->enableDownload()

Filament 也支持 spatie/laravel-medialibrary。更多信息可查看插件文档

富文本编辑器

富文本编辑器让你可以编辑和预览HTML内容,上传图片。

use Filament\Forms\Components\RichEditor;
 
RichEditor::make('content')

你可以使用一系列便捷方法启用/禁用工具栏按钮:

use Filament\Forms\Components\RichEditor;
 
RichEditor::make('content')
->toolbarButtons([
'attachFiles',
'blockquote',
'bold',
'bulletList',
'codeBlock',
'h2',
'h3',
'italic',
'link',
'orderedList',
'redo',
'strike',
'undo',
])
RichEditor::make('content')
->disableToolbarButtons([
'attachFiles',
'codeBlock',
])
RichEditor::make('content')
->disableAllToolbarButtons()
->enableToolbarButtons([
'bold',
'bulletList',
'italic',
'strike',
])

你可以使用配置方法自定义图片如何上传:

use Filament\Forms\Components\RichEditor;
 
RichEditor::make('content')
->fileAttachmentsDisk('s3')
->fileAttachmentsDirectory('attachments')
->fileAttachmentsVisibility('private')

Markdown编辑器

Markdown 编辑器让你可以编辑和预览 markdown 内容,也可以上传图片。

use Filament\Forms\Components\MarkdownEditor;
 
MarkdownEditor::make('content')

你可以使用一系列便捷方法启用/禁用工具栏按钮:

use Filament\Forms\Components\MarkdownEditor;
 
MarkdownEditor::make('content')
->toolbarButtons([
'attachFiles',
'bold',
'bulletList',
'codeBlock',
'edit',
'italic',
'link',
'orderedList',
'preview',
'strike',
])
MarkdownEditor::make('content')
->disableToolbarButtons([
'attachFiles',
'codeBlock',
])
MarkdownEditor::make('content')
->disableAllToolbarButtons()
->enableToolbarButtons([
'bold',
'bulletList',
'edit',
'italic',
'preview',
'strike',
])

你可以使用配置方法自定义图片如何上传:

use Filament\Forms\Components\MarkdownEditor;
 
MarkdownEditor::make('content')
->fileAttachmentsDisk('s3')
->fileAttachmentsDirectory('attachments')
->fileAttachmentsVisibility('private')

Hidden

Hidden 组件让你可以在表单内创建一个带值的隐藏(hidden)字段。

use Filament\Forms\Components\Hidden;
 
Hidden::make('token')

Repeater

Repeater 组件让你在重复的表单组件中输出JSON数组。

use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
 
Repeater::make('members')
->schema([
TextInput::make('name')->required(),
Select::make('role')
->options([
'member' => 'Member',
'administrator' => 'Administrator',
'owner' => 'Owner',
])
->required(),
])
->columns(2)

我们建议您将数据以 JSON 字段的形式保存在数据库中。另外,如果使用了 Eloquent,确保对该字段进行了 array cast。

如上例所示,组件的 schema 可以在 schema() 方法中定义:

use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\TextInput;
 
Repeater::make('members')
->schema([
TextInput::make('name')->required(),
// ...
])

如果你想要使用多重 schema 代码块定义 Repeater 并使之可以以任何顺序重复,请使用 builer

使用 defaultItems() 方法,Repeater 默认会有一些特定数量的空项目。

use Filament\Forms\Components\Repeater;
 
Repeater::make('members')
->schema([
// ...
])
->defaultItems(3)

你可以设置标签,自定义显示在添加项目按钮上的文本。

use Filament\Forms\Components\Repeater;
 
Repeater::make('members')
->schema([
// ...
])
->createItemButtonLabel('Add member')

你也可以阻止用户添加项目,删除项目或者在 Repeater 内移动项目:

use Filament\Forms\Components\Repeater;
 
Repeater::make('members')
->schema([
// ...
])
->disableItemCreation()
->disableItemDeletion()
->disableItemMovement()

你可以使用 minItems()maxItems() 方法自定义创建的 Item 数量:

use Filament\Forms\Components\Repeater;
 
Repeater::make('members')
->schema([
// ...
])
->minItems(1)
->maxItems(10)

可折叠

Repeater 可以是可折叠的 collapsible(), 用来在长表单中选择性隐藏内容:

use Filament\Forms\Components\Repeater;
 
Repeater::make('qualifications')
->schema([
// ...
])
->collapsible()

你也可以让它在默认情况下是折叠的:

use Filament\Forms\Components\Repeater;
 
Repeater::make('qualifications')
->schema([
// ...
])
->collapsed()

克隆项目

使用 cloneable() 方法,可以允许复制 repeater 项:

use Filament\Forms\Components\Repeater;
 
Repeater::make('qualifications')
->schema([
// ...
])
->cloneable()

自动从关联中填充数据

你可以使用 Repeater 的 relationship() 方法配置关联,自动检索和保存 Repeater 数据:

use App\Models\App;
use Filament\Forms\Components\Repeater;
 
Repeater::make('qualifications')
->relationship()
->schema([
// ...
])

要启用该功能,你也必须按照关联字段区域的指示进行设置。如果你使用后台面板,可以忽略此步

排序项目

默认情况下,对 Repeater 项目进行排序是被禁用的。这是因为关联模型需要有一个 sort 字段,用来保存关联记录的顺序。要启用排序,你可以使用 orderable() 方法:

use Filament\Forms\Components\Repeater;
 
HasManyRepeater::make('qualifications')
->relationship('qualifications')
->schema([
// ...
])
->orderable()

本例假定你的关联模型中有一个 sort 字段。

如果你使用了像 spatie/eloquent-sortable这样的包,使用了像 order_column 这样的字段名作为排序字段,你可以将其作为参数传入 orderable() 中:

use Filament\Forms\Components\Repeater;
 
Repeater::make('qualifications')
->relationship('qualifications')
->schema([
// ...
])
->orderable('order_column')

网格布局

你可以使用 grid() 方法组织 Repeater 项目:

use Filament\Forms\Components\Repeater;
 
Repeater::make('members')
->schema([
// ...
])
->grid(2)

该方法与gridcolumns() 方法相似,接收相同的参数选项。让你可以在不同临界点自定义网格列数。

项目标签

你可以使用 itemLabel() 方法,为 Repeater 项目添加标签:

use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\TextInput;
 
Repeater::make('members')
->schema([
TextInput::make('name')
->lazy(),
])
->itemLabel(fn (array $state): ?string => $state['name'] ?? null),

如果你希望项目标签动态更新,那么使用 $state 获取的字段,应该是 reactive()lazy() 的。

使用 $get() 访问父级字段值

所有表单组件都可以使用 $get()$set()获取其他字段的值。然而,在 Repeater 中使用可能会碰到异常。

这是因为默认情况下,$get()$set() 被限定在当前repeater项目中。也就是说,你可以在repeater项目中的其他字段交互,而不需要了解该表单属于哪一个repeater条目。

其结果是,当你不能与repeater字段进行互动时,会感到困惑。我们使用 ../ 语法来解决此问题 - $get('../../parent_field_name')

假设你的表单数据结构如下:

[
'client_id' => 1,
 
'repeater' => [
'item1' => [
'service_id' => 2,
],
],
]

你需要在 repeater 项目中检索 client_id 的值。

$get() 用于检索当前的repeater项, 因此 $get('client_id') 意味着 $get('repeater.item1.client_id')

你可以使用 ../ 切换到数据结构的上一级,因此 $get('../client_id') 相当于 $get('repeater.client_id')$get('../../client_id') 相当于 $get('client_id')

Builder

类似于Repeater,Builder 组件让你可以以JSON数组的形式输出重复的表单组件。所有不同的是,Repeater 只定义了一个需要重复的表单的 shema,而 Builder 允许定义多个 schema 代码块,你可以以任何顺序进行排序。这有助于创建更高级的数组结构。

Builder 组件的主要用途,是使用预定义的代码块来搭建网页内容。下例在页面内容中为不同的元素定义了多个代码块。在你网站的前端,你可以使用 JSON 或者你需要的格式遍历每个代码块。

use Filament\Forms\Components\Builder;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\MarkdownEditor;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
 
Builder::make('content')
->blocks([
Builder\Block::make('heading')
->schema([
TextInput::make('content')
->label('Heading')
->required(),
Select::make('level')
->options([
'h1' => 'Heading 1',
'h2' => 'Heading 2',
'h3' => 'Heading 3',
'h4' => 'Heading 4',
'h5' => 'Heading 5',
'h6' => 'Heading 6',
])
->required(),
]),
Builder\Block::make('paragraph')
->schema([
MarkdownEditor::make('content')
->label('Paragraph')
->required(),
]),
Builder\Block::make('image')
->schema([
FileUpload::make('url')
->label('Image')
->image()
->required(),
TextInput::make('alt')
->label('Alt text')
->required(),
]),
])

建议在数据库中以 JSON 方式保存 Builder 的数据。另外,如果使用的是 Eloquent,确保对字段进行 array 造型。

如上例所示,代码块被定义在组件的 blocks() 方法中。代码块(Block) 是 Builder\Block 对象,有一个唯一名称以及一个组件 schema:

use Filament\Forms\Components\Builder;
use Filament\Forms\Components\TextInput;
 
Builder::make('content')
->blocks([
Builder\Block::make('heading')
->schema([
TextInput::make('content')->required(),
// ...
]),
// ...
])

默认情况下,代码块的标签会基于其名称自动生成。要重写代码块标签,请使用 label() 方法。如果你想使用本地化翻译字符,以此自定义标签是个有效的方式:

use Filament\Forms\Components\Builder;
 
Builder\Block::make('heading')->label(__('blocks.heading'))

Block 也可以添加图标,显示在标签旁边。icon() 方法接收Blade图标组件作为参数:

use Filament\Forms\Components\Builder;
 
Builder\Block::make('heading')->icon('heroicon-o-bookmark')

你也可以使用 minItems()maxItems() 方法自定义可以创建的项目数量:

use Filament\Forms\Components\Builder;
use Filament\Forms\Components\TextInput;
 
Builder::make('content')
->blocks([
// ...
])
->minItems(1)
->maxItems(10)

可折叠

可以使用 collapsible() 方法,在长表单中选择性隐藏内容:

use Filament\Forms\Components\Builder;
 
Builder::make('content')
->blocks([
// ...
])
->collapsible()

可以默认折叠所有项目:

use Filament\Forms\Components\Builder;
 
Builder::make('content')
->blocks([
// ...
])
->collapsed()

标签输入框

标签(Tag)输入组件让你可以和标签列表交互。

默认情况下,标签以 JOSN 方式保存:

use Filament\Forms\Components\TagsInput;
 
TagsInput::make('tags')

如果你使用 Eloquent 保存 JSON 标签,你应该在模型属性中添加 array cast

use Illuminate\Database\Eloquent\Model;
 
class Post extends Model
{
protected $casts = [
'tags' => 'array',
];
 
// ...
}

你也可以用分隔字符串保存 Tag 标签。要启用这种方法,在 separator() 方法传入分隔字符:

use Filament\Forms\Components\TagsInput;
 
TagsInput::make('tags')->separator(',')

标签输入框可以使用自动补全建议。要启用这个功能,在 suggestions() 方法中传入一个数组:

use Filament\Forms\Components\TagsInput;
 
TagsInput::make('tags')
->suggestions([
'tailwindcss',
'alpinejs',
'laravel',
'livewire',
])

Filament 也支持 spatie/laravel-tags。更多信息可查看插件文档

文本区

文本区(textarea)让你可以和多行字符串进行交互:

use Filament\Forms\Components\Textarea;
 
Textarea::make('description')

通过定义 rows()cols() 方法来调整文本区的大小:

use Filament\Forms\Components\Textarea;
 
Textarea::make('description')
->rows(10)
->cols(20)

你可以设置 minLength()maxLength() 方法限制字符串长度。这些方法同时添加了前端和后端验证器:

use Filament\Forms\Components\Textarea;
 
Textarea::make('description')
->minLength(50)
->maxLength(500)

键值对

键值对(key-value)字段让你可以与一维 JSON 对象进行交互:

use Filament\Forms\Components\KeyValue;
 
KeyValue::make('meta')

你可以使用 keyLable()valueLabel() 方法,自定义键值对字段的标签:

use Filament\Forms\Components\KeyValue;
 
KeyValue::make('meta')
->keyLabel('Property name')
->valueLabel('Property value')

你也可以禁止用户添加行,删除行,或者编辑行:

use Filament\Forms\Components\KeyValue;
 
KeyValue::make('meta')
->disableAddingRows()
->disableDeletingRows()
->disableEditingKeys()

你可以允许用户在表格中对行重新排序:

use Filament\Forms\Components\KeyValue;
 
KeyValue::make('meta')
->reorderable()

你也可以使用 keyPlaceholder()valuePlaceholder() 方法为键值对字段添加占位符:

use Filament\Forms\Components\KeyValue;
 
KeyValue::make('meta')
->keyPlaceholder('Property name')
->valuePlaceholder('Property value')

颜色选择器

颜色选择器(Color Picker)组件让你可以以一系列格式选择颜色。

默认情况下,组件使用HEX(16进制)格式:

use Filament\Forms\Components\ColorPicker;
 
ColorPicker::make('color')

另外,你可以使用不同格式:

use Filament\Forms\Components\ColorPicker;
 
ColorPicker::make('hsl_color')->hsl()
ColorPicker::make('rgb_color')->rgb()
ColorPicker::make('rgba_color')->rgba()

视图字段

除了创建自定义字段,你可以创造"视图(view)"字段,让你可以不需要创建另外的PHP类就可以创建自定义字段。

use Filament\Forms\Components\ViewField;
 
ViewField::make('notifications')->view('filament.forms.components.range-slider')

在你的视图内,你可以使用 Livewire和 Alpine.js 与表单组件进行状态交互。

视图可以使用 $getStatePath() 闭包获取字段类的 Livewire 属性 path。你可以使用 wire:model进行数据绑定, 或者 $wire.entangle 与 Alpine.js 进行交互。

使用 Livewire's entangle 与 Alpine.js 共享 state:

<x-forms::field-wrapper
:id="$getId()"
:label="$getLabel()"
:label-sr-only="$isLabelHidden()"
:helper-text="$getHelperText()"
:hint="$getHint()"
:hint-icon="$getHintIcon()"
:required="$isRequired()"
:state-path="$getStatePath()"
>
<div x-data="{ state: $wire.entangle('{{ $getStatePath() }}').defer }">
<!-- Interact with the `state` property in Alpine.js -->
</div>
</x-forms::field-wrapper>

或者,你可以使用wire:model将其值绑定到Livewire属性:

<x-forms::field-wrapper
:id="$getId()"
:label="$getLabel()"
:label-sr-only="$isLabelHidden()"
:helper-text="$getHelperText()"
:hint="$getHint()"
:hint-icon="$getHintIcon()"
:required="$isRequired()"
:state-path="$getStatePath()"
>
<input wire:model.defer="{{ $getStatePath() }}" />
</x-forms::field-wrapper>

创建自定义字段

你也可以创建自定义的表单类和视图,用来在应用内复用,甚至向社区发布插件。

如果你只是需要创建一次性使用的简单自定义字段,你可以使用视图字段来渲染自定义模板文件。

要自定义表单字段类和视图,你可以使用以下命令:

php artisan make:form-field RangeSlider

该命令会创建如下字段类:

use Filament\Forms\Components\Field;
 
class RangeSlider extends Field
{
protected string $view = 'filament.forms.components.range-slider';
}

在你的视图内,你可以使用 Livewire 和 Alpine.js 与表单组件进行状态交互。

视图可以使用 $getStatePath() 闭包获取字段类的 Livewire 属性path。你可以使用 wire:model 进行数据绑定,或者$wire.entangle 与 Alpine.js 进行交互:

<x-forms::field-wrapper
:id="$getId()"
:label="$getLabel()"
:label-sr-only="$isLabelHidden()"
:helper-text="$getHelperText()"
:hint="$getHint()"
:hint-icon="$getHintIcon()"
:required="$isRequired()"
:state-path="$getStatePath()"
>
<div x-data="{ state: $wire.entangle('{{ $getStatePath() }}').defer }">
<!-- Interact with the `state` property in Alpine.js -->
</div>
</x-forms::field-wrapper>

需要帮助? 加入论坛 或者打开 GitHub讨论

喜欢Filament?

Filament 中文文档由 laravel-filament.cn 翻译整理。站长用爱发电,希望为英文阅读不畅的朋友提供快速掌握Filament框架的途径。文档的翻译,社区的运营维护都需要时间精力上的付出。如果文档社区使你受益,如果你想支持站长...

打赏