概述
简介
表格是 Web 应用中展示记录列表的常见 UI 模式。Filament 提供基于 PHP 的 API 来定义功能丰富的表格,同时也高度可定制。


定义表格列
任何表格的基础都是行与列。Filament 使用 Eloquent 获取表格行的数据,而你负责定义该行中使用的列。
Filament 内置了许多列类型,你可以在此查看完整列表。甚至可以创建自己的自定义列类型,按任意方式展示数据。
列以对象数组的形式存放在 $table->columns() 方法中:
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('title'),
TextColumn::make('slug'),
IconColumn::make('is_featured')
->boolean(),
]);
}

使列可排序与可搜索
你可以通过链式调用方法轻松修改列。例如,可使用 searchable() 方法使列可搜索。此时表格中会出现搜索框,你就能按该列的值筛选行:
use Filament\Tables\Columns\TextColumn;
TextColumn::make('title')
->searchable()

你可以使多列可搜索,Filament 能同时在其中任意列中搜索匹配项。
你也可以使用 sortable() 方法使列可排序。这会在列标题上添加排序按钮,点击后将按该列对表格排序:
use Filament\Tables\Columns\TextColumn;
TextColumn::make('title')
->sortable()

从列中访问关联数据
你也可以在列中显示属于关联关系的数据。例如,若有一个属于 User 模型(文章作者)的 Post 模型,你可以在表格中显示用户的姓名:
use Filament\Tables\Columns\TextColumn;
TextColumn::make('author.name')

此时,Filament 会在 Post 模型上查找 author 关联,然后显示该关联的 name 属性。我们称之为「点记法」(dot notation),你可以用它显示任意关联的任意属性,甚至嵌套关联。Filament 会用这种点记法为你预加载(eager-load)该关联的结果。
有关列关联的更多信息,请参阅关联部分。
在现有列旁添加新列
columns() 方法会重新定义表格的全部列,但有时你可能希望向现有配置添加列,而不完全覆盖。当你有应出现在多个表格中的全局列配置时,这尤其有用。
Filament 为此提供了 pushColumns() 方法。与会替换整个列配置的 columns() 不同,pushColumns() 会将新列追加到任何现有列之后。
与服务提供者(如 AppServiceProvider)的 boot() 方法中的全局表格设置结合使用时尤其强大:
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
Table::configureUsing(function (Table $table) {
$table
->pushColumns([
TextColumn::make('created_at')
->label('Created')
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('updated_at')
->label('Updated')
->sortable()
->toggleable(isToggledHiddenByDefault: true),
]);
});定义表格筛选器
除了使列 searchable(),从而允许用户通过搜索列内容来筛选表格外,你也可以允许用户以其他方式筛选表格行。筛选器可在 $table->filters() 方法中定义:
use Filament\Tables\Filters\Filter;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
public function table(Table $table): Table
{
return $table
->columns([
// ...
])
->filters([
Filter::make('is_featured')
->query(fn (Builder $query) => $query->where('is_featured', true)),
SelectFilter::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
]),
]);
}

本例中我们定义了 2 个表格筛选器。表格上角现在会有一个「筛选」图标按钮。点击后会打开包含我们所定义的 2 个筛选器的下拉菜单。
第一个筛选器渲染为复选框。勾选后,表格中仅显示 featured 行;取消勾选则显示所有行。
第二个筛选器渲染为选择下拉框。用户选择某个选项后,仅显示具有该 status 的行;未选择任何选项时显示所有行。
你可以使用任意 schema 组件 来构建筛选器的 UI。例如,你可以创建自定义日期范围筛选器。
定义表格操作
Filament 的表格可以使用操作。它们是可添加到任意表格行末尾,甚至表格页眉的按钮。例如,你可能希望在页眉有「创建」新记录的操作,并在每行上有「编辑」和「删除」操作。批量操作可在选中表格记录时执行代码。
use App\Models\Post;
use Filament\Actions\Action;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
public function table(Table $table): Table
{
return $table
->columns([
// ...
])
->recordActions([
Action::make('feature')
->action(function (Post $record) {
$record->is_featured = true;
$record->save();
})
->hidden(fn (Post $record): bool => $record->is_featured),
Action::make('unfeature')
->action(function (Post $record) {
$record->is_featured = false;
$record->save();
})
->visible(fn (Post $record): bool => $record->is_featured),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}

本例中我们为表格行定义了 2 个操作。第一个是「feature」操作。点击后会将记录的 is_featured 属性设为 true——这写在 action() 方法中。使用 hidden() 方法,若记录已经 featured,该操作会被隐藏。第二个是「unfeature」操作。点击后会将记录的 is_featured 属性设为 false。使用 visible() 方法,若记录未 featured,该操作会被隐藏。
我们还定义了一个批量操作。定义批量操作后,表格每一行都会有复选框。该批量操作是 Filament 内置的,会删除所有选中的记录。不过,你也可以轻松编写自己的自定义批量操作。


操作也可以打开模态框向用户请求确认,并在其中渲染表单以收集额外数据。建议阅读操作文档,了解它们在 Filament 中的广泛能力。
分页
默认情况下,Filament 表格会分页。用户可在每页 5、10、25 和 50 条记录之间选择。若记录数超过所选数量,用户可使用分页按钮在页面间导航。


自定义分页选项
你可以通过向 paginated() 方法传入选项,自定义每页记录数选择器的选项:
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->paginated([10, 25, 50, 100, 'all']);
}WARNING
使用非常大的数字和 all 时请注意,大量记录可能导致性能问题。
自定义默认分页页选项
要自定义默认显示的记录数,请使用 defaultPaginationPageOption() 方法:
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->defaultPaginationPageOption(25);
}INFO
请确保默认分页页选项包含在分页选项中。
显示指向第一页和最后一页的分页链接
要添加指向第一页和最后一页的「两端」链接,请使用 extremePaginationLinks() 方法:
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->extremePaginationLinks();
}

使用简单分页
你可以使用 paginationMode(PaginationMode::Simple) 方法启用简单分页:
use Filament\Tables\Enums\PaginationMode;
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->paginationMode(PaginationMode::Simple);
}

使用游标分页
你可以使用 paginationMode(PaginationMode::Cursor) 方法启用游标分页:
use Filament\Tables\Enums\PaginationMode;
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->paginationMode(PaginationMode::Cursor);
}

防止查询字符串与分页页码冲突
默认情况下,Livewire 将分页状态存储在 URL 查询字符串的 page 参数中。若同一页面有多个表格,一个表格的分页状态可能被另一个表格的状态覆盖。
要修复此问题,你可以定义 $table->queryStringIdentifier(),为该表格返回唯一的查询字符串标识符:
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->queryStringIdentifier('users');
}禁用分页
默认情况下表格会分页。要禁用分页,应使用 $table->paginated(false) 方法:
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->paginated(false);
}记录 URL(可点击的行)
你可以使用 $table->recordUrl() 方法让表格行完全可点击:
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Model;
public function table(Table $table): Table
{
return $table
->recordUrl(
fn (Model $record): string => route('posts.edit', ['record' => $record]),
);
}使用 resource 表格时,每行的 URL 通常已经为你设置好,但可以调用此方法覆盖每行的默认 URL。
你也可以在新标签页中打开 URL:
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->openRecordUrlInNewTab();
}重排序记录
要允许用户在表格中通过拖放重排序记录,可以使用 $table->reorderable() 方法:
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->reorderable('sort');
}本例中的 sort 数据库列将用于存储表格中记录的顺序。每当你用该列对数据库查询排序时,记录会按所定义的顺序返回。若模型使用了批量赋值保护,还需要将 sort 属性添加到 $fillable 数组中。
使表格可重排序后,表格上会出现一个新按钮,用于切换重排序模式。


reorderable() 方法接受用于存储记录顺序的列名。若你使用 spatie/eloquent-sortable 之类的包,顺序列为 order_column,则可改用该列:
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->reorderable('order_column');
}reorderable() 方法还将布尔条件作为第二个参数,允许你有条件地启用重排序:
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->reorderable('sort', auth()->user()->isAdmin());
}你可以传入 direction 参数为 desc,按降序而非升序重排序记录:
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->reorderable('sort', direction: 'desc');
}在重排序时启用分页
重排序模式下会禁用分页,以便你在页面之间移动记录。重排序时使用分页通常体验不佳,但若希望覆盖此行为,请使用 $table->paginatedWhileReordering():
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->paginatedWhileReordering();
}自定义重排序触发操作
要自定义重排序触发按钮,可以使用 reorderRecordsTriggerAction() 方法,传入返回操作的闭包。所有可用于自定义操作触发按钮的方法都可以使用:
use Filament\Actions\Action;
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->reorderRecordsTriggerAction(
fn (Action $action, bool $isReordering) => $action
->button()
->label($isReordering ? 'Disable reordering' : 'Enable reordering'),
);
}

在重排序前后运行代码
你可以使用 beforeReordering() 和 afterReordering() 方法在记录重排序之前或之后运行代码。两个方法都接受一个函数,该函数会收到新的记录键 $order 数组:
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->reorderable('sort')
->beforeReordering(function (array $order): void {
// Runs before records are reordered in the database.
})
->afterReordering(function (array $order): void {
// Runs after records are reordered in the database.
});
}自定义表格页眉
你可以使用 $table->heading() 方法为表格添加标题:
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->heading('Clients')
->columns([
// ...
]);你也可以使用 $table->description() 方法在标题下方添加描述:
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->heading('Clients')
->description('Manage your clients here.')
->columns([
// ...
]);

你可以将视图传给 $table->header() 方法,以自定义整个页眉 HTML:
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->header(view('tables.header', [
'heading' => 'Clients',
]))
->columns([
// ...
]);轮询表格内容
你可以使用 $table->poll() 方法轮询表格内容,使其按设定间隔刷新:
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->poll('10s');
}延迟加载
数据量大的表格可能需要较长时间加载,此时可以使用 deferLoading() 方法异步加载表格数据:
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->deferLoading();
}使用 Laravel Scout 搜索记录
虽然 Filament 不提供与 Laravel Scout 的直接集成,但你可以使用带 whereKey() 子句的 searchUsing() 方法,按 Scout 结果筛选查询:
use App\Models\Post;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
public function table(Table $table): Table
{
return $table
->searchUsing(fn (Builder $query, string $search) => $query->whereKey(Post::search($search)->keys()));在正常情况下,Scout 内部使用 whereKey()(whereIn())方法检索结果,因此使用它没有性能损失。
要显示全局搜索输入框,表格中至少需要有一列是 searchable()。或者,若你已用 Scout 控制哪些列可搜索,也可以直接对整个表格调用 searchable():
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->searchable();
}设置表格行样式
斑马纹表格行
要启用斑马纹表格行,可以使用 striped() 方法:
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->striped();
}

自定义行类名
你可能希望根据记录数据有条件地设置行样式。可以通过 $table->recordClasses() 方法指定要应用到行上的 CSS 类字符串或数组来实现:
use App\Models\Post;
use Closure;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Model;
public function table(Table $table): Table
{
return $table
->recordClasses(fn (Post $record) => match ($record->status) {
'draft' => 'draft-post-table-row',
'reviewing' => 'reviewing-post-table-row',
'published' => 'published-post-table-row',
default => null,
});
}

全局设置
要自定义所有表格使用的默认配置,可以在服务提供者的 boot() 方法中调用静态 configureUsing() 方法。该函数会对每个被创建的表格运行:
use Filament\Tables\Enums\FiltersLayout;
use Filament\Tables\Table;
Table::configureUsing(function (Table $table): void {
$table
->reorderableColumns()
->filtersLayout(FiltersLayout::AboveContentCollapsible)
->paginationPageOptions([10, 25, 50]);
});