开始
准备Livewire组件
实现 HasTable 接口,使用 InteractsWithTable trait:
<?php
namespace App\Http\Livewire;
use Filament\Tables;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class ListPosts extends Component implements Tables\Contracts\HasTable // [tl! focus]
{
use Tables\Concerns\InteractsWithTable; // [tl! focus]
public function render(): View
{
return view('list-posts');
}
}
在 Livewire 组件视图中,渲染表格:
<div>
{{ $this->table }}
</div>
然后,在 getTableQuery() 方法中添加表格所需要的 Eloquent 查询:
<?php
namespace App\Http\Livewire;
use App\Models\Post;
use Filament\Tables;
use Illuminate\Contracts\View\View;
use Illuminate\Database\Eloquent\Builder;
use Livewire\Component;
class ListPosts extends Component implements Tables\Contracts\HasTable
{
use Tables\Concerns\InteractsWithTable;
protected function getTableQuery(): Builder // [tl! focus:start]
{
return Post::query();
} // [tl! focus:end]
public function render(): View
{
return view('list-posts');
}
}
最后,将表格字段、过滤器和动作添加到 Livewire 组件中:
<?php
namespace App\Http\Livewire;
use App\Models\Post;
use Filament\Tables;
use Illuminate\Contracts\View\View;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Livewire\Component;
class ListPosts extends Component implements Tables\Contracts\HasTable
{
use Tables\Concerns\InteractsWithTable;
protected function getTableQuery(): Builder
{
return Post::query();
}
protected function getTableColumns(): array // [tl! focus:start]
{
return [ // [tl! collapse:start]
Tables\Columns\ImageColumn::make('author.avatar')
->size(40)
->rounded(),
Tables\Columns\TextColumn::make('title'),
Tables\Columns\TextColumn::make('author.name'),
Tables\Columns\BadgeColumn::make('status')
->colors([
'danger' => 'draft',
'warning' => 'reviewing',
'success' => 'published',
]),
Tables\Columns\IconColumn::make('is_featured')->boolean(),
]; // [tl! collapse:end]
}
protected function getTableFilters(): array
{
return [ // [tl! collapse:start]
Tables\Filters\Filter::make('published')
->query(fn (Builder $query): Builder => $query->where('is_published', true)),
Tables\Filters\SelectFilter::make('status')
->options([
'draft' => 'Draft',
'in_review' => 'In Review',
'approved' => 'Approved',
]),
]; // [tl! collapse:end]
}
protected function getTableActions(): array
{
return [ // [tl! collapse:start]
Tables\Actions\Action::make('edit')
->url(fn (Post $record): string => route('posts.edit', $record)),
]; // [tl! collapse:end]
}
protected function getTableBulkActions(): array
{
return [ // [tl! collapse:start]
Tables\Actions\BulkAction::make('delete')
->label('Delete selected')
->color('danger')
->action(function (Collection $records): void {
$records->each->delete();
})
->requiresConfirmation(),
]; // [tl! collapse:end]
} // [tl! focus:end]
public function render(): View
{
return view('list-posts');
}
}
在浏览器中访问 Livewire 组件,你就能看到表格了。
分页
默认情况下,表格是分页的。要禁用此功能,你可以在 Livewire 组件上重写 isTablePaginationEnabled() 方法:
<?php
namespace App\Http\Livewire;
use App\Models\Post;
use Filament\Tables;
use Illuminate\Contracts\View\View;
use Illuminate\Database\Eloquent\Builder;
use Livewire\Component;
class ListPosts extends Component implements Tables\Contracts\HasTable
{
use Tables\Concerns\InteractsWithTable;
protected function getTableQuery(): Builder
{
return Post::query();
}
protected function getTableColumns(): array
{
return [
Tables\Columns\TextColumn::make('title'),
Tables\Columns\TextColumn::make('author.name'),
];
}
protected function isTablePaginationEnabled(): bool // [tl! focus:start]
{
return false;
} // [tl! focus:end]
public function render(): View
{
return view('list-posts');
}
}
在 Livewire 组件上重写 getTableRecordsPerPageSelectOptions() 方法,你可以自定义每页显示数的可选项:
<?php
namespace App\Http\Livewire;
use App\Models\Post;
use Filament\Tables;
use Illuminate\Contracts\View\View;
use Illuminate\Database\Eloquent\Builder;
use Livewire\Component;
class ListPosts extends Component implements Tables\Contracts\HasTable
{
use Tables\Concerns\InteractsWithTable;
protected function getTableQuery(): Builder
{
return Post::query();
}
protected function getTableColumns(): array
{
return [
Tables\Columns\TextColumn::make('title'),
Tables\Columns\TextColumn::make('author.name'),
];
}
protected function getTableRecordsPerPageSelectOptions(): array // [tl! focus:start]
{
return [10, 25, 50, 100];
} // [tl! focus:end]
public function render(): View
{
return view('list-posts');
}
}
默认情况下,Livewire 将分页状态保存在URL查询字符串的 page 参数中。如果你在同一页面有多张表格,这就会导致一张表格的分页状态可能会被其他表格的分页状态所覆盖。
要解决这一问题,你可以在组件上定义 getTableQueryStringIdentifier(),为该表格返回唯一查询字符串标识符:
protected function getTableQueryStringIdentifier(): string
{
return 'users';
}
简单分页
你可以在 Livewire 组件上重写 paginateTableQuery() 方法,使用简单分页:
use Illuminate\Contracts\Pagination\Paginator;
use Illuminate\Database\Eloquent\Builder;
protected function paginateTableQuery(Builder $query): Paginator
{
return $query->simplePaginate($this->getTableRecordsPerPage() == -1 ? $query->count() : $this->getTableRecordsPerPage());
}
使用Laravel Scount搜索记录
Filament 并没有提供直接与 Laravel Scout 整合的方式,你可以在 Livewire 组件内重写方法进行整合。
首先,确保表格搜索框可见:
public function isTableSearchable(): bool
{
return true;
}
然后,使用 whereIn 条款过滤 Scount 的查询结果:
use App\Models\Post;
use Illuminate\Database\Eloquent\Builder;
protected function applySearchToTableQuery(Builder $query): Builder
{
if (filled($searchQuery = $this->getTableSearchQuery())) {
$query->whereIn('id', Post::search($searchQuery)->keys());
}
return $query;
}
Scout 内部使用 whereIn() 方法查询结果,因此使用它不会有性能代偿。
可点击的行
记录URL
通过重写 Livewire 组件上的 getTableRecordUrlUsing() 方法,你可以让表格行完全可点击:
use Closure;
use Illuminate\Database\Eloquent\Model;
protected function getTableRecordUrlUsing(): Closure
{
return fn (Model $record): string => route('posts.edit', ['record' => $record]);
}
本例中,点击每个post都会转到 posts.edit 路由。
如果你要为一个特定的字段重写 URL,或者在点击字段时运行 Livewire 操作,请查看表格字段文档。
记录 Action
另外,你也可以配置表格行,用以触发 Action,替代打开 URL:
use Closure;
use Filament\Tables\Actions\Action;
use Filament\Tables\Actions\DeleteAction;
protected function getTableRecordActionUsing(): ?Closure
{
return fn (): string => 'edit';
}
禁用可点击行
如果你想完全禁用整行的点击操作,你可以在 Livewire 组件中重写 getTableRecordActionUsing() 方法,并返回 null:
use Closure;
protected function getTableRecordActionUsing(): ?Closure
{
return null;
}
记录样式类
你可能希望根据记录数据在不同行内展示不同样式。使用 getTableRecordClassesUsing() 方法,指定一个 CSS 类字符串或数组,可以使之实现:
use Closure;
use Illuminate\Database\Eloquent\Model;
protected function getTableRecordClassesUsing(): ?Closure
{
return fn (Model $record) => match ($record->status) {
'draft' => 'opacity-30',
'reviewing' => [
'border-l-2 border-orange-600',
'dark:border-orange-300' => config('tables.dark_mode'),
],
'published' => 'border-l-2 border-green-600',
default => null,
};
}
这些类不会被 Tailwind 自动编译。如果你想要使用没有在 Blade 中文件中使用的 Tailwind CSS 类,你需要更新 tailwind.config.js 文件中的 content 配置项,使之同时扫描对应 PHP 文件中的类:
export default {
content: [
'./app/Filament/**/*.php',
],
}
另外,你也可以将这些类添加到安全列表:
export default {
safelist: [
'border-green-600',
'border-l-2',
'border-orange-600',
'dark:border-orange-300',
'opacity-30',
],
}