跳到主要内容
版本:3.0

布局

传统表格布局的问题

传统表格因为响应式适配能力差而名声不佳。在移动端,在水平方向上渲染较长内容时,只有有限的灵活性:

  • 允许用户水平滚动查看表格内容
  • 在较小的设备上隐藏不重要的列字段

这两者在 Filament 上都能实现。表格会在内容溢出时自动水平滚动,而且你可以基于浏览器的响应式临界点显示或隐藏字段。要实现该功能,请使用 visibleFrom()hiddenFrom() 方法:

use Filament\Tables\Columns\TextColumn;

TextColumn::make('slug')
->visibleFrom('md')

这很好,但仍然存在一个明显的问题 - 在移动设备上,用户在不滚动的情况下无法同时看到表行中的许多信息

值得庆幸的是,Filament 可以让您在不接触 HTML 或 CSS 的情况下构建响应式的类表接口。通过这些布局,您可以在每个响应断点处准确定义内容在表行中的显示位置。

Table with responsive layout
Table with responsive layout on mobile

移动端上允许列堆叠

让我们来了解一个组件 - Split

use Filament\Support\Enums\FontWeight;
use Filament\Tables\Columns\Layout\Split;
use Filament\Tables\Columns\TextColumn;

Split::make([
ImageColumn::make('avatar')
->circular(),
TextColumn::make('name')
->weight(FontWeight::Bold)
->searchable()
->sortable(),
TextColumn::make('email'),
])
Table with a split layout
Table with a split layout on mobile

Split 组件用于包裹列字段,并允许他们在移动端堆叠。

默认情况下,Split 中的列会始终显示在彼此旁边。不过,你可以使用 from() 选择一个该行为开始的响应式临界点。在此临界点之前,列字段将会彼此堆叠在一起:

use Filament\Support\Enums\FontWeight;
use Filament\Tables\Columns\Layout\Split;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;

Split::make([
ImageColumn::make('avatar')
->circular(),
TextColumn::make('name')
->weight(FontWeight::Bold)
->searchable()
->sortable(),
TextColumn::make('email'),
])->from('md')

本例中,这些列只会在 md 临界点以上的设备中水平展开显示:

Table with a split layout on desktop
Table with a stacked layout on mobile

防止列中创建空格

像表格列字段一样,Split 会自动调整空格以确保每个列能适当分开。你可以使用 grow(false) 防止该行为。本例中,我们将确保头像紧贴着名称字段:

use Filament\Support\Enums\FontWeight;
use Filament\Tables\Columns\Layout\Split;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;

Split::make([
ImageColumn::make('avatar')
->circular()
->grow(false),
TextColumn::make('name')
->weight(FontWeight::Bold)
->searchable()
->sortable(),
TextColumn::make('email'),
])

其他允许 grow() 的列字段将进行调整,以消耗最新释放的空格:

Table with a column that doesn't grow
Table with a column that doesn't grow on mobile

Split 内堆叠

在 Split 内,你可以将多个列字段在垂直方向上堆叠(Stack)。这就让你可以在桌面端的少数列字段中展示更多数据:

use Filament\Support\Enums\FontWeight;
use Filament\Tables\Columns\Layout\Split;
use Filament\Tables\Columns\Layout\Stack;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;

Split::make([
ImageColumn::make('avatar')
->circular(),
TextColumn::make('name')
->weight(FontWeight::Bold)
->searchable()
->sortable(),
Stack::make([
TextColumn::make('phone')
->icon('heroicon-m-phone'),
TextColumn::make('email')
->icon('heroicon-m-envelope'),
]),
])
Table with a stack
Table with a stack on mobile

在移动端隐藏 Stack

类似于单独的列,您可以根据浏览器的响应式临界点选择隐藏 Stack。为此,可以使用 visibleFrom() 方法:

use Filament\Support\Enums\FontWeight;
use Filament\Tables\Columns\Layout\Split;
use Filament\Tables\Columns\Layout\Stack;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;

Split::make([
ImageColumn::make('avatar')
->circular(),
TextColumn::make('name')
->weight(FontWeight::Bold)
->searchable()
->sortable(),
Stack::make([
TextColumn::make('phone')
->icon('heroicon-m-phone'),
TextColumn::make('email')
->icon('heroicon-m-envelope'),
])->visibleFrom('md'),
])
Table with a stack
Table with no stack on mobile

对齐堆叠内容

默认情况下,Stack 内的列字段在开始处对齐。你可以将 Stack 内的列字段的对齐方式设置为 Alignment::CenterAlignment::End

use Filament\Support\Enums\Alignment;
use Filament\Support\Enums\FontWeight;
use Filament\Tables\Columns\Layout\Split;
use Filament\Tables\Columns\Layout\Stack;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;

Split::make([
ImageColumn::make('avatar')
->circular(),
TextColumn::make('name')
->weight(FontWeight::Bold)
->searchable()
->sortable(),
Stack::make([
TextColumn::make('phone')
->icon('heroicon-m-phone')
->grow(false),
TextColumn::make('email')
->icon('heroicon-m-envelope')
->grow(false),
])
->alignment(Alignment::End)
->visibleFrom('md'),
])

请确保将 Stack 内的列字段设置为 grow(false),否则它们会伸展至填满 Stack 的整个宽度并遵循它们自己的对齐配置而非 Stack 的对齐方式。

Table with a stack aligned right

堆叠内容间隔

默认情况下,不同列字段之间的堆叠内容在垂直方向上没有 padding。可以使用 space() 方法添加,该方法接收 123,对应于 Tailwind 空格大小

use Filament\Tables\Columns\Layout\Stack;
use Filament\Tables\Columns\TextColumn;

Stack::make([
TextColumn::make('phone')
->icon('heroicon-m-phone'),
TextColumn::make('email')
->icon('heroicon-m-envelope'),
])->space(1)

使用网格控制列宽

有时,当列字段包含很多内容时,使用 Split 会出现不一致的宽度。这是因为它内部是使用 Flexbox 驱动,并且每行独自控制分配多少空格给内容。

相反,你可以使用 Grid 布局,它使用 CSS 网格布局,允许你控制列宽:

use Filament\Tables\Columns\Layout\Grid;
use Filament\Tables\Columns\TextColumn;

Grid::make([
'lg' => 2,
])
->schema([
TextColumn::make('phone')
->icon('heroicon-m-phone'),
TextColumn::make('email')
->icon('heroicon-m-envelope'),
])

lg 断点开始,这些列字段在网格内始终会消费同样的宽度。

你也可以在其他断点处自定义网格的列数:

use Filament\Tables\Columns\Layout\Grid;
use Filament\Tables\Columns\Layout\Stack;
use Filament\Tables\Columns\TextColumn;

Grid::make([
'lg' => 2,
'2xl' => 4,
])
->schema([
Stack::make([
TextColumn::make('name'),
TextColumn::make('job'),
]),
TextColumn::make('phone')
->icon('heroicon-m-phone'),
TextColumn::make('email')
->icon('heroicon-m-envelope'),
])

你甚至可以控制每个组件在每个临界点所消费的网格列数:

use Filament\Tables\Columns\Layout\Grid;
use Filament\Tables\Columns\Layout\Stack;
use Filament\Tables\Columns\TextColumn;

Grid::make([
'lg' => 2,
'2xl' => 5,
])
->schema([
Stack::make([
TextColumn::make('name'),
TextColumn::make('job'),
])->columnSpan([
'lg' => 'full',
'2xl' => 2,
]),
TextColumn::make('phone')
->icon('heroicon-m-phone')
->columnSpan([
'2xl' => 2,
]),
TextColumn::make('email')
->icon('heroicon-m-envelope'),
])

可折叠内容

使用像 Split 或者 Stack 这样的列布局时,你也可以添加可折叠的内容。如果你不想一次性在表格中展示所有数据,但仍然希望用户在必要时不必离开当前页面访问数据,这个功能非常有用。

Split 和 Stack 组件可以设为 collapsible,不过有一个专用的 Panel 组件提供了预定义样式的背景色和边框圆角,用以将可折叠内容和其他内容分离开来:

use Filament\Support\Enums\FontWeight;
use Filament\Tables\Columns\Layout\Panel;
use Filament\Tables\Columns\Layout\Split;
use Filament\Tables\Columns\Layout\Stack;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;

[
Split::make([
ImageColumn::make('avatar')
->circular(),
TextColumn::make('name')
->weight(FontWeight::Bold)
->searchable()
->sortable(),
]),
Panel::make([
Stack::make([
TextColumn::make('phone')
->icon('heroicon-m-phone'),
TextColumn::make('email')
->icon('heroicon-m-envelope'),
]),
])->collapsible(),
]

你也可以使用 collapsed(false) 方法使面板默认展开:

use Filament\Tables\Columns\Layout\Panel;
use Filament\Tables\Columns\Layout\Split;
use Filament\Tables\Columns\TextColumn;

Panel::make([
Split::make([
TextColumn::make('phone')
->icon('heroicon-m-phone'),
TextColumn::make('email')
->icon('heroicon-m-envelope'),
])->from('md'),
])->collapsed(false)
Table with collapsible content
Table with collapsible content on mobile

将记录排列到网格中

有时,你会发现,比起列表格式,数据更适合于以网格格式排列。Filament 也能处理这种情况!

只需使用 $table->contentGrid() 方法:

use Filament\Tables\Table;

public function table(Table $table): Table
{
return $table
->contentGrid([
'md' => 2,
'xl' => 3,
]);
}

本例中,行数据将以网格形式展示:

  • 在移动端,它只会显示为 1 列。
  • md 临界点开始,会显示为 2 列。
  • xl 临界点以上,会显示为 3 列。

这些设置完全是可自定义的,从 sm2xl 的任何临界点都能包含 112 列。

Table with grid layout
Table with grid layout on mobile

自定义 HTML

使用 View 组件,你可以将自定义 HTML 添加到表格中。它甚至也可以是可折叠的 collapsible()

use Filament\Support\Enums\FontWeight;
use Filament\Tables\Columns\Layout\Split;
use Filament\Tables\Columns\Layout\View;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;

[
Split::make([
ImageColumn::make('avatar')
->circular(),
TextColumn::make('name')
->weight(FontWeight::Bold)
->searchable()
->sortable(),
]),
View::make('users.table.collapsible-row-content')
->collapsible(),
]

现在,新建一个 /resources/views/users/table/collapsible-row-content.blade.php 文件,并添加你自己的 HTML。你可以使用 $getRecord() 访问表格记录:

<p class="px-4 py-3 bg-gray-100 rounded-lg">
<span class="font-medium">
Email address:
</span>

<span>
{{ $getRecord()->email }}
</span>
</p>

嵌入其他组件

你甚至可以将列字段或者其他布局组件传入到 components() 方法中:

use Filament\Support\Enums\FontWeight;
use Filament\Tables\Columns\Layout\Split;
use Filament\Tables\Columns\Layout\View;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;

[
Split::make([
ImageColumn::make('avatar')
->circular(),
TextColumn::make('name')
->weight(FontWeight::Bold)
->searchable()
->sortable(),
]),
View::make('users.table.collapsible-row-content')
->components([
TextColumn::make('email')
->icon('heroicon-m-envelope'),
])
->collapsible(),
]

现在, 在 Blade 文件中渲染这些组件:

<div class="px-4 py-3 bg-gray-100 rounded-lg">
<x-filament-tables::columns.layout
:components="$getComponents()"
:record="$getRecord()"
:record-key="$recordKey"
/>
</div>