表格
Overview
简介
表格是一种常见的 UI 模式,用于在 Web 应用中显示记录列表。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(),
]);
}
上例中,表格中有 3 列。前两列显示文本 - 表格中每行的标题及 slug。第三列显示图标,根据 is_featured 值是否为真显示为绿色勾选或者红色打叉图标,
让列可排序及可搜索
你可以通过将方法链式调用到列上来轻松修改列。例如,你可以使用 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 属性。我们称之为“点语法”,你可以用它来展示任何关联的任何属性,甚至是嵌套关联。Filament 使用点语法来饥渴加载关联的结果。
更多有关列关联的信息,请查阅相关关联文档。
在现有列旁边添加新列
虽然 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',
]),
]);
}
此例中,我们定义了两个表格过滤器。表格顶部角落现在有一个“过滤器”图标按钮。点击它将打开一个下拉菜单,其中包含我们定义的两个过滤器。
第一个过滤器渲染成复选框。选中时,仅显示表格中的选中行。取消选中时,将显示所有行。
第二个过滤器渲染成选择下拉菜单。当用户选择一个选项时,仅显示具有该状态的行。当未选择任何选项时,将显示所有行。
你可以使用任何 Schema 组件来构建过滤器的用户界面。例如,你可以创建自定义日期范围过滤器。
定义表格操作
Filament 的表格可以使用 Action。这些按钮可以添加到任意表格行的末尾,甚至可以添加到表格的 header。例如,你可能希望在表头中“创建”一条新记录,然后在每行上执行“编辑”和“删除”操作。批量操作 可用于在选中表格中的记录时执行代码。
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(),
]),
]);
}
上例中,我们为表格行定义了两个操作。第一个操作是 “feature” 操作。点击后,它会将记录的 is_featured 属性设置为 true——该属性在action() 方法中写入。使用 hidden() 方法,如果记录已是 featured,则隐藏该操作。第二个操作是 “unfeature” 操作。点击后,它会将记录的 is_featured 属性设置为 false。使用 visible() 方法,如果记录不是 featured,则隐藏该操作。
我们还定义了一个批量操作。定义批量操作后,表格中的每一行都会有一个复选框。此批量操作内置于 Filament,它将删除所有选定的记录。当然,你也可以轻松编写自己的自定义批量操作。
Action 还可以打开模态框来请求用户确认,并在其中渲染表单以收集额外数据。建议你阅读 Actions 文档,以了解更多有关其在 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']);
}
NOTE
请注意,使用非常大的数字和 all 时,大量记录可能会导致性能问题。
自定义默认分页页面选项
要自定义显示的默认记录数,请使用 defaultPaginationPageOption() 方法:
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->defaultPaginationPageOption(25);
}
NOTE
请确保分页选项中包含默认分页选项。
Disabling records per page persistence in the user’s session
By default, the selected number of records per page is persisted in the user’s session. To disable this behavior, use the persistRecordsPerPageInSession() method:
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->persistRecordsPerPageInSession(false);
}
显示链接到首页和最后一页的分页链接
使用 extremePaginationLinks() 方法向第一页和最后一页添加“端点(extreme)”链接:
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);
}
使用 Cursor 分页
使用 paginationMode(PaginationMode::Cursor) 方法,你可以使用光标(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]),
);
}
当使用资源 表时,每行的 URL 通常已经为你设置好了,但可以调用此方法来覆盖每行的默认 URL。
TIP
你还可以重写特定列的 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());
}
You can pass a direction parameter as desc to reorder the records in descending order instead of ascending:
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() 方法,并传入一个返回 Action 的闭包。所有自定义 Action 触发按钮中可以使用的方法,都可以在此处使用:
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'),
);
}
Running code before and after reordering
You may run code before or after a record is reordered using the beforeReordering() and afterReordering() methods. Both methods accept a function that receives the new $order array of record keys:
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 直接交互的集成,你可以在 searchUsing() 方法中使用 whereKey() 子句去过滤用于 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();
}
Persisting the table state in the user’s session
Filament can remember a table’s filters, search, sort, grouping, column manager, and records per page state in the user’s session, so it is restored when they return to the table. Each feature has its own method, but you can toggle all of them at once using the persistInSession() method:
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->columns([
// ...
])
->persistInSession();
}
Passing false disables every kind of session persistence, including the column manager, which is persisted by default:
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->columns([
// ...
])
->persistInSession(false);
}
设置表格行样式
条纹状表格行
要让表格行启用斑马条纹,你可以使用 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]);
});
Edit on GitHubStill need help? Join our Discord community or open a GitHub discussion