Skip to content
全部文档

布局

传统表格布局的问题

传统表格以响应性差而著称。在移动端,渲染横向较长的内容时,可用的灵活性相当有限:

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

这两点在 Filament 中都可以实现。表格溢出时会自动水平滚动,你也可以根据浏览器的响应式 breakpoint 选择显示和隐藏列。为此,可以使用 visibleFrom()hiddenFrom() 方法:

php
use Filament\Tables\Columns\TextColumn;

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

这样可以,但仍有一个明显问题——在移动端,用户若不滚动,一次只能在表格行中看到很少信息

Filament 提供两种解决方案:

  1. **简单堆叠** - 使用 `stackedOnMobile()` 在移动端自动垂直堆叠所有单元格,无需更改列定义
  2. **自定义布局** - 使用 `Split`、`Stack` 及其他布局组件,精细控制内容在各断点的呈现方式

在移动端堆叠表格单元格

让表格响应式的最简单方式是在表格上使用 stackedOnMobile() 方法。这会在移动屏幕上将传统水平表格布局自动转换为垂直卡片式布局,同时在较大屏幕上保留标准表格外观:

php
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;

public function table(Table $table): Table
{
    return $table
        ->columns([
            TextColumn::make('name')
                ->searchable()
                ->sortable(),
            TextColumn::make('email'),
            TextColumn::make('phone'),
            TextColumn::make('job'),
        ])
        ->stackedOnMobile();
}
桌面端的移动堆叠布局表格桌面端的移动堆叠布局表格
移动端的堆叠布局表格移动端的堆叠布局表格

在移动端,每行显示为卡片,列标签位于其值上方。若有可排序列,移动端表格顶部会出现排序下拉框,让用户无需传统表头即可排序。也支持批量选择,复选框会出现在页眉区域。

当你希望快速实现响应式且无需重构列时,此方法很合适。不过,对于更复杂的布局,或需精细控制内容在不同断点的呈现方式时,你可能更想使用下文所述的布局组件。

自定义列布局

Filament 让你无需改动 HTML 或 CSS 即可构建响应式类表格界面。这些布局让你精确指定内容在表格行中、在每个响应式断点上出现的位置。

带响应式布局的表格带响应式布局的表格
移动端带响应式布局的表格移动端带响应式布局的表格

允许列在移动端堆叠

我们来介绍一个组件——Split

php
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'),
])
带 Split 布局的表格带 Split 布局的表格
移动端带 Split 布局的表格移动端带 Split 布局的表格

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

默认情况下,split 内的列会始终并排显示。不过,你可以选择该行为从哪个响应式 breakpoint 开始 from()。在此之前,列会上下堆叠:

php
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 breakpoint 设备起水平并排显示:

桌面端带 Split 布局的表格桌面端带 Split 布局的表格
移动端带堆叠布局的表格移动端带堆叠布局的表格

阻止列产生空白

Split 与表格列一样,会自动调整空白以确保每列有适当间距。你可以使用 grow(false) 阻止此行为。在本例中,我们确保头像图片紧贴姓名列:

php
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() 的其他列会调整以占用新腾出的空间:

禁用 grow 的列的表格禁用 grow 的列的表格
移动端禁用 grow 的列的表格移动端禁用 grow 的列的表格

在 Split 内堆叠

在 split 内,你可以将多列垂直堆叠。这让你能在桌面端用更少的列显示更多数据:

php
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'),
    ]),
])
带 Stack 的表格带 Stack 的表格
移动端带 Stack 的表格移动端带 Stack 的表格

在移动端隐藏 Stack

与单独的列类似,你可以根据浏览器的响应式 breakpoint 选择隐藏 stack。为此,可以使用 visibleFrom() 方法:

php
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'),
])
带 Stack 的表格带 Stack 的表格
移动端无 Stack 的表格移动端无 Stack 的表格

对齐堆叠内容

默认情况下,stack 内的列对齐到起始端。你也可以选择将 stack 内的列对齐到 Alignment::CenterAlignment::End

php
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 的对齐。

右对齐 Stack 的表格右对齐 Stack 的表格

堆叠内容间距

默认情况下,堆叠内容的列之间没有垂直内边距。要添加间距,可以使用 space() 方法,接受 123,对应 Tailwind 的间距比例

php
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 Grid Layout,让你控制列宽:

php
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 breakpoint 起,这些列在网格中始终占用相等宽度。

带网格列布局的表格带网格列布局的表格

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

php
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'),
    ])

你甚至可以控制每个组件在各 breakpoint 占用多少网格列:

php
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 组件,提供预设样式的背景色和圆角,以将可折叠内容与其余部分分隔开:

php
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) 方法默认展开面板:

php
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)
带可折叠内容的表格带可折叠内容的表格
移动端带可折叠内容的表格移动端带可折叠内容的表格

将记录排列为网格

有时你会发现数据更适合网格格式而非列表。Filament 也能处理!

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

php
use Filament\Tables\Columns\Layout\Stack;
use Filament\Tables\Table;

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

在本例中,行会以网格显示:

  • 在移动端,仅显示为 1 列。
  • 从 `md` [breakpoint](https://tailwindcss.com/docs/responsive-design#overview) 起,显示为 2 列。
  • 从 `xl` [breakpoint](https://tailwindcss.com/docs/responsive-design#overview) 起,显示为 3 列。

这些设置完全可自定义,从 sm2xl 的任意 breakpoint 都可以包含 112 列。

带网格布局的表格带网格布局的表格
移动端带网格布局的表格移动端带网格布局的表格

自定义 HTML

你可以使用 View 组件向表格添加自定义 HTML。它甚至可以是 collapsible()

php
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() 访问表格记录:

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

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

嵌入其他组件

你甚至可以将列或其他布局组件传给 components() 方法:

php
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 文件中渲染这些组件:

blade
<div class="px-4 py-3 bg-gray-100 rounded-lg">
    @foreach ($getComponents() as $layoutComponent)
        {{ $layoutComponent
            ->record($getRecord())
            ->recordKey($getRecordKey())
            ->rowLoop($getRowLoop())
            ->renderInLayout() }}
    @endforeach
</div>