news 2026/9/10 14:26:49

Filament 表格布局完全指南:从移动端堆叠到自定义行布局

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Filament 表格布局完全指南:从移动端堆叠到自定义行布局

Filament 表格布局完全指南:从移动端堆叠到自定义行布局

【免费下载链接】filamentA powerful open-source UI framework for Laravel • Build and ship apps & admin panels fast with Livewire项目地址: https://gitcode.com/GitHub_Trending/fi/filament

Filament 的 Tables 包不仅提供了功能完备的数据列与筛选器,还内置了一套强大的响应式布局系统,让开发者无需编写 HTML/CSS 即可构建在手机、平板与桌面端都表现良好的表格界面。本文基于 packages/tables/docs/05-layout.md 展开,结合 tables 包源码,完整讲解stackedOnMobile()移动端堆叠、Split/Stack/Grid/Panel/View布局组件、可折叠内容以及contentGrid()记录网格等核心能力,读完你将能够为任意列表页设计出可精细控制、适配各断点的响应式行布局。

传统表格布局的困境

传统 HTML 表格在响应式方面是出了名的难处理。在移动端,面对横向超长的内容,通常只有两种做法:

  1. 允许用户横向滚动,以查看更多的表格内容;
  2. 在较小设备上隐藏次要列

Filament 对这两种方案都提供了原生支持:表格在内容溢出时会自动横向滚动;同时你也可以基于浏览器的响应式 Tailwind 断点(sm/md/lg/xl/2xl)来决定列的显示与隐藏,使用visibleFrom()hiddenFrom()方法:

use Filament\Tables\Columns\TextColumn; TextColumn::make('slug') ->visibleFrom('md')

这种做法固然可行,但存在一个明显的问题——在移动端,用户不滚动就很难在同一行中看到足够多的信息

Filament 为解决这个问题提供了两套方案:

  1. 简单堆叠(Simple stacking):使用stackedOnMobile()在移动端自动将所有单元格垂直堆叠,且完全不需要改动你的列定义;
  2. 自定义布局(Custom layouts):使用SplitStack等布局组件,精确控制内容在每个断点下的呈现方式。

移动端堆叠表格单元格:stackedOnMobile()

让表格响应式的最简方式是在表格上调用stackedOnMobile()。它会自动把传统的横向表格布局在移动端转换为垂直的卡片式布局,而在大屏上保持标准表格外观:

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(); }

在移动端,每一行会以卡片的形式展示,列标签显示在其值的上方。如果存在可排序的列,移动端表格顶部会出现一个排序下拉框,用户无需传统的表头行即可排序;批量选择同样受支持,复选框会出现在表头区域。

从源码看,该方法定义于 CanBeStackedOnMobile.php 中:stackedOnMobile()接收一个布尔值或闭包,内部存储在isStackedOnMobile属性中,最终由isStackedOnMobile()求值,因此你甚至可以写成->stackedOnMobile(fn () => auth()->user()->isMobile())这类条件逻辑。

这种方式适合需要快速获得响应式效果、且不想重构列定义的场景。但如果布局较复杂、或需要对不同断点下的内容呈现做精细控制,则推荐使用下面介绍的布局组件。

自定义列布局

Filament 允许你完全不接触 HTML 或 CSS,就构建出响应式的"类表格"界面。这些布局组件可以精确决定每一行中的内容出现在哪里、以及每个响应式断点下的表现。

Split:让列在移动端堆叠

先介绍第一个组件——Split

use Filament\Support\Enums\FontWeight; use Filament\Tables\Columns\ImageColumn; 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 内的列会一直并排展示。你也可以通过from()指定一个响应式断点,让并排行为从该断点才开始;在此之前,列会上下堆叠:

use Filament\Support\Enums\FontWeight; use Filament\Tables\Columns\ImageColumn; 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'), ])->from('md')

在这个示例中,列只在md断点及以上的设备上并排显示,小于md时全部垂直堆叠。from()由 HasFromBreakpoint.php 提供,底层渲染时会在容器上添加{breakpoint}:fi-ta-split这样的 Tailwind 类,由 CSS 决定对应断点下的布局行为(见 Split.php)。

阻止列产生空白:grow(false)

Split与普通表格列一样,会自动调整空白以保证各列之间有合理的比例分隔。如果你不希望某个列占据多余空白,可以对其使用grow(false)。下面的示例让头像图片紧贴姓名列:

use Filament\Support\Enums\FontWeight; use Filament\Tables\Columns\ImageColumn; use Filament\Tables\Columns\Layout\Split; 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(false)的能力来自CanGrowtrait(被布局基类 Component.php 引入),渲染时对应容器会带上fi-growable类。

在 Split 内堆叠:Stack

Split内部,你可以用Stack把多列垂直堆叠起来,从而在桌面上用更少的列展示更多数据:

use Filament\Support\Enums\FontWeight; use Filament\Tables\Columns\ImageColumn; use Filament\Tables\Columns\Layout\Split; use Filament\Tables\Columns\Layout\Stack; 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,使用visibleFrom()方法:

use Filament\Support\Enums\FontWeight; use Filament\Tables\Columns\ImageColumn; use Filament\Tables\Columns\Layout\Split; use Filament\Tables\Columns\Layout\Stack; 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内的列按起始位置(start)对齐。你也可以把列对齐到Alignment::CenterAlignment::End

use Filament\Support\Enums\Alignment; use Filament\Support\Enums\FontWeight; use Filament\Tables\Columns\ImageColumn; use Filament\Tables\Columns\Layout\Split; use Filament\Tables\Columns\Layout\Stack; 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 的。该能力来自HasAlignmenttrait,渲染时会在容器上追加fi-align-{alignment}类(见 Stack.php)。

堆叠内容的间距

默认情况下,堆叠内容之间没有垂直内边距。要增加间距,可使用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)

从 Stack.php 的源码可以看到,1/2/3分别映射为fi-gap-smfi-gap-mdfi-gap-lg三个间距类。

用 Grid 控制列宽

某些情况下,当列包含大量内容时,Split会产生不一致的宽度。这是因为Split内部基于 Flexbox 实现,每一行独立决定如何分配空间。

此时可以改用Grid布局,它基于 CSS Grid Layout,让你可以精确控制列宽:

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

甚至可以控制每个组件在各个断点下占据多少网格列(columnSpan):

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

从 Grid.php 的源码看,Grid::make()的默认列数为2,并且当你传入纯整数时(如Grid::make(2)),内部会自动转换为['lg' => 2];渲染时容器会带上fi-ta-grid类,并根据每个断点的列数决定使用小间距(fi-gap-sm,单列时)还是大间距(fi-gap-lg,多列时)。

可折叠内容

当你使用SplitStack这类列布局时,还可以添加可折叠内容。这在"不想一次性展示全部数据,但又希望用户无需离开页面即可按需查看"时非常有用。

SplitStack组件本身都可以设置collapsible(),此外还有一个专门的Panel组件,它提供了预置的背景色与圆角,用来把可折叠内容与其余部分区分开:

use Filament\Support\Enums\FontWeight; use Filament\Tables\Columns\ImageColumn; use Filament\Tables\Columns\Layout\Panel; use Filament\Tables\Columns\Layout\Split; use Filament\Tables\Columns\Layout\Stack; 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(), ]

Panel组件在渲染时会给容器加上fi-ta-panel类(见 Panel.php),这就是预置背景与圆角样式的来源。

默认情况下可折叠内容处于折叠状态,你也可以通过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)

从布局基类 Component.php 的源码可以看到,collapsible()设置isCollapsible标志,collapsed()会同时调用collapsible()并把折叠状态写入isCollapsed属性(支持闭包求值)。

将记录排列为网格:contentGrid()

如果你的数据更适合以网格而非列表的形式展示,Filament 同样支持。只需使用$table->contentGrid()方法:

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断点起:2 列;
  • xl断点起:3 列。

这些配置完全可自定义,sm2xl之间的任何断点都可以设置112列。该方法定义于 HasContent.php,该 trait 同时提供了content()(自定义整行内容视图)与contentFooter()(内容底部视图)方法。

自定义 HTML:View 组件

你可以使用View组件向表格行中添加自定义 HTML,它同样支持collapsible()

use Filament\Support\Enums\FontWeight; use Filament\Tables\Columns\ImageColumn; use Filament\Tables\Columns\Layout\Split; use Filament\Tables\Columns\Layout\View; 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()方法向View组件传入列或其他布局组件:

use Filament\Support\Enums\FontWeight; use Filament\Tables\Columns\ImageColumn; use Filament\Tables\Columns\Layout\Split; use Filament\Tables\Columns\Layout\View; 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"> @foreach ($getComponents() as $layoutComponent) {{ $layoutComponent ->record($getRecord()) ->recordKey($getRecordKey()) ->rowLoop($getRowLoop()) ->renderInLayout() }} @endforeach </div>

这里调用的renderInLayout()正是布局组件渲染的核心入口——它在布局基类 Component.php 中实现:如果组件被隐藏则返回null,否则根据columnSpan/columnStartgrowhiddenFrom/visibleFrom组装出带网格列与响应式类的容器属性,再渲染组件自身的 HTML。

布局组件的底层骨架

所有布局组件(SplitStackGridPanelView)都继承自Filament\Tables\Columns\Layout\Component(见 Component.php),它聚合了以下能力:

  • schema()/components():接收列或子布局组件的数组(也支持闭包惰性求值),getComponents()会自动为每个子组件设置所属布局,使其能通过getTable()访问到宿主表格;
  • getColumns():递归收集布局树中的所有Column,这保证了排序、搜索、隐藏等功能对布局内的列依然生效;
  • collapsible()/collapsed()/isCollapsed():可折叠能力,折叠状态支持闭包动态求值;
  • renderInLayout():按columnSpangrowhiddenFrom/visibleFrom等配置输出带响应式类的包裹容器;
  • 通过CanGrowCanSpanColumnsCanBeHiddenHasRecordHasRowLoopObjectHasExtraAttributes等 trait 获得与普通列一致的横向能力。

布局选择建议

  • 想要快速响应式:直接用$table->stackedOnMobile(),一行代码即可;
  • 需要突出头像、姓名等主信息,次要信息分组收纳Split+Stack组合,配合from()visibleFrom()alignment()space()精细调节;
  • 列内容多、宽度不一致:改用Grid+columnSpan,用 CSS Grid 保证列宽一致性;
  • 次要数据默认隐藏、按需展开:使用Panel::make(...)->collapsible()Split/Stackcollapsible()
  • 数据本身适合卡片网格contentGrid()配合Stack布局,可替代传统列表;
  • 需要完全自由的 HTMLView组件 + Blade 模板,必要时用components()嵌入标准列组件。

布局组件在tables包中的实现均位于 packages/tables/src/Columns/Layout 目录,相关表格级能力(stackedOnMobilecontentGrid)分别见 CanBeStackedOnMobile.php 与 HasContent.php。结合本文的示例与源码指引,你可以在实际资源列表页中自由组合这些布局,为不同屏幕尺寸的用户提供一致的浏览体验。

【免费下载链接】filamentA powerful open-source UI framework for Laravel • Build and ship apps & admin panels fast with Livewire项目地址: https://gitcode.com/GitHub_Trending/fi/filament

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 14:15:31

第18章:RabbitMQ 队列类型选型——Classic / Quorum / Stream / Volatile

1. 项目背景 三节点成群后&#xff0c;架构评审最容易变成口号会&#xff1a;「全部 quorum&#xff0c;金融级」「日志也 quorum&#xff0c;别丢」「网关回调也 quorum&#xff0c;省得选」。另一种口号是「全用经典队列&#xff0c;咱们刚第 16 章验过」。两种都会在大促翻…

作者头像 李华