Filament Schemas 布局组件完全指南:Grid 栅格系统、Flex、Fieldset 与容器查询
2026/9/10 5:00:46 网站建设 项目流程

Filament Schemas 布局组件完全指南:Grid 栅格系统、Flex、Fieldset 与容器查询

【免费下载链接】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 的 Schemas 布局体系为核心,系统讲解如何利用columns()columnSpan()columnStart()columnOrder()构建响应式多列布局,并深入剖析GridFlexFieldset三个基础布局组件的用法与源码实现。读完本文,你将掌握 Filament 布局组件的全部核心 API、基于 Tailwind 断点与容器查询(container queries)的响应式方案,以及延迟加载、间距控制、自定义 HTML 属性等进阶技巧,可直接用于表单、Infolist、Panel 页面等场景。

布局组件全景

Filament 的栅格系统允许你使用任意布局组件创建响应式、多列布局。packages/schemas/docs/02-layouts.md中给出了内置布局组件的完整清单,它们都位于Filament\Schemas\Components命名空间:

  • Grid
  • Flex
  • Fieldset
  • Section
  • Tabs
  • Wizard
  • Callout
  • Empty state

你也可以创建自定义布局组件以按任意方式展示组件。布局组件可无限嵌套子 schema,配合表单字段、Infolist 条目与 Prime 组件 组合出任意复杂的界面。

栅格系统:columns()方法

所有布局组件都提供columns()方法,支持两种传参方式:

  • 整数columns(2)表示在lg断点及以上使用 2 列,所有更小设备只显示 1 列。
  • 数组:以断点为键、列数为值,例如columns(['md' => 2, 'xl' => 4])会在中等设备显示 2 列、超宽设备显示 4 列。更小设备的默认断点为 1 列,除非你显式提供default键。

断点(smmdlgxl2xl)由 Tailwind 定义,对应视口宽度依次约为 640px、768px、1024px、1280px、1536px。

从源码看,columns()定义于 packages/schemas/src/Concerns/HasColumns.php:传入整数时会被自动包装为['lg' => $columns],传入数组时与原配置合并;它同时接受Closure,运行时通过evaluate()解析动态值。getAllColumns()会基于默认值['default' => 1, 'sm' => null, 'md' => null, 'lg' => null, 'xl' => null, '2xl' => null]填充未指定的断点。若当前对象是Schema且存在父组件,还会继承父组件的列配置(见HasColumns.php第 64-66 行)。

除了静态值,columns()也接受函数动态计算列数,并可向函数注入各种工具参数(如Get$record$operation$livewire$component等,详见 Schema 总览)。例如根据当前用户权限动态决定列数:

use Filament\Schemas\Components\Grid; Grid::make(fn (): array => [ 'lg' => auth()->user()->isAdmin() ? 4 : 6, ])->schema([ // ... ]);

列跨度:columnSpan()

除了指定布局组件自身有多少列,还可以用columnSpan()指定某个组件在父栅格中占据多少列:

  • 整数columnSpan(2)表示在lg断点及以上占据 2 列,更小设备只占 1 列。
  • 数组columnSpan(['md' => 2, 'xl' => 4])表示中等设备占 2 列、超宽设备占 4 列;更小设备默认 1 列,除非提供default键。
  • 'full'columnSpan('full')表示在lg断点及以上占满父栅格整行,更小设备占 1 列。
  • columnSpanFull():在所有设备上占满父栅格整行,与父栅格列数无关。

源码位于 packages/support/src/Concerns/CanSpanColumns.php:整数跨度会被包装为['default' => 1, 'lg' => $span]columnSpanFull()实际等价于columnSpan(['default' => 'full'])。由于columnSpan()Filament\Support\Concerns\CanSpanColumnstrait 提供的,所有组件(而不只是布局组件)都天然具备该方法——这正是文档示例中表单字段可以直接调用columnSpan()的原因。

列起始:columnStart()

若希望组件从栅格的指定列开始,使用columnStart()

  • 整数columnStart(2)表示在lg断点及以上从第 2 列开始,更小设备从第 1 列开始。
  • 数组columnStart(['md' => 2, 'xl' => 4])表示中等设备从第 2 列开始、超宽设备从第 4 列开始;更小设备默认第 1 列,除非提供default键。

例如,让文本框始终从栅格中间开始(无论栅格有多少列):

use Filament\Forms\Components\TextInput; use Filament\Schemas\Components\Grid; Grid::make() ->columns([ 'sm' => 3, 'xl' => 6, '2xl' => 8, ]) ->schema([ TextInput::make('name') ->columnStart([ 'sm' => 2, 'xl' => 3, '2xl' => 4, ]), // ... ])

此例中,栅格在小屏为 3 列、超宽为 6 列、超超宽为 8 列;文本框分别从第 2、3、4 列开始,效果上始终位于栅格中点。

columnStart()的实现同样位于 CanSpanColumns.php,整数会包装为['lg' => $start]。方法同样接受Closure动态计算。

列排序:columnOrder()

在不改变 HTML 结构中组件顺序的前提下,可用columnOrder()控制组件在栅格中的视觉顺序

  • 整数columnOrder(2)表示在lg断点及以上按顺序值 2 显示;更小设备使用默认顺序,除非提供default键。
  • 数组columnOrder(['md' => 2, 'xl' => 4])分别设置中等、超宽设备上的顺序值。
  • 闭包columnOrder(fn () => 1)动态计算顺序。
use Filament\Forms\Components\TextInput; use Filament\Schemas\Components\Grid; Grid::make() ->columns(3) ->schema([ TextInput::make('first') ->columnOrder(3), // This will appear last TextInput::make('second') ->columnOrder(1), // This will appear first TextInput::make('third') ->columnOrder(2), // This will appear second ])

也可结合断点做响应式排序,在不同屏幕尺寸下呈现不同顺序:

use Filament\Forms\Components\TextInput; use Filament\Schemas\Components\Grid; Grid::make() ->columns([ 'sm' => 2, 'lg' => 3, ]) ->schema([ TextInput::make('title') ->columnOrder([ 'default' => 1, 'lg' => 3, ]), TextInput::make('description') ->columnOrder([ 'default' => 2, 'lg' => 1, ]), TextInput::make('category') ->columnOrder([ 'default' => 3, 'lg' => 2, ]), ])

此例中,小屏顺序为 title、description、category;大屏顺序变为 description、category、title。

columnOrder()实现在 packages/support/src/Concerns/CanOrderColumns.php,整数包装为['lg' => $order],同样支持闭包动态计算。

一个完整的响应式栅格示例

由于所有布局组件都支持columns(),可以把栅格配置直接写到 Section 等布局组件上,在内部再配合columnSpan()columnOrder()精细控制每个字段:

use Filament\Forms\Components\TextInput; use Filament\Schemas\Components\Section; Section::make() ->columns([ 'sm' => 3, 'xl' => 6, '2xl' => 8, ]) ->schema([ TextInput::make('name') ->columnSpan([ 'default' => 1, 'sm' => 2, 'xl' => 3, '2xl' => 4, ]) ->columnOrder([ 'default' => 2, 'xl' => 1, ]), TextInput::make('email') ->columnSpan([ 'default' => 1, 'xl' => 2, ]) ->columnOrder([ 'default' => 1, 'xl' => 2, ]), // ... ])

行为解读:小于sm时每行 1 列,sm及以上 3 列,xl及以上 6 列,2xl及以上 8 列;name 字段在sm起占 2 列、xl起占 3 列、2xl起占 4 列,email 在xl起占 2 列。排序方面,小于xl时 email 在前、name 在后;xl及以上则相反。这正是「不改 DOM、纯配置化响应式」的典型用法,其中TextInput等文本输入组件作为表单字段天然继承了columnSpan()能力。

基础布局组件

Grid 组件

所有布局组件都支持columns(),但Grid是唯一一个显式栅格语法的布局组件:无需额外样式,直接把列配置传给Grid::make()即可:

use Filament\Schemas\Components\Grid; Grid::make([ 'default' => 1, 'sm' => 2, 'md' => 3, 'lg' => 4, 'xl' => 6, '2xl' => 8, ]) ->schema([ // ... ])

从 packages/schemas/src/Components/Grid.php 的源码可见,Grid::make()的默认列数为2,其渲染逻辑(toEmbeddedHtml())仅仅输出一个包裹childSchema<div>,因此没有任何额外的卡片、标题等视觉样式。测试用例 tests/src/Schemas/Components/GridTest.php 也验证了「默认 2 列」「可用整数构造」「可用响应式数组构造」三种行为。

Flex 组件

Flex基于 CSS Flexbox 实现弹性宽度布局,它不使用 Filament 的栅格系统:

use Filament\Forms\Components\Textarea; use Filament\Forms\Components\TextInput; use Filament\Forms\Components\Toggle; use Filament\Schemas\Components\Section; use Filament\Schemas\Components\Flex; Flex::make([ Section::make([ TextInput::make('title'), Textarea::make('content'), ]), Section::make([ Toggle::make('is_published'), Toggle::make('is_featured'), ])->grow(false), ])->from('md')

此例中第一个 Section 会grow()吃掉剩余水平空间,第二个 Section 保持自身所需宽度,形成经典的「弹性宽度侧栏」效果。

  • from()控制切换到水平布局的 Tailwind 断点(smmdlgxl2xl):本例在md及以上水平并排,更小设备则垂直堆叠。其实现位于 packages/support/src/Concerns/HasFromBreakpoint.php,Flex 通过use HasFromBreakpoint引入。
  • grow()定义于 packages/support/src/Concerns/CanGrow.php,默认true,可传布尔值或闭包动态控制。

grow()from()同样支持闭包与工具注入。tests/src/Schemas/Components/FlexTest.php 覆盖了alignment()verticalAlignment()from()的静态值与闭包写法,以及多种渲染场景。

Fieldset 组件

Fieldset用于把字段分组:每个 fieldset 自带标签(label)、边框,默认是两列栅格

use Filament\Schemas\Components\Fieldset; Fieldset::make('Label') ->columns([ 'default' => 1, 'md' => 2, 'xl' => 3, ]) ->schema([ // ... ])

「默认两列」可以从源码证实:packages/schemas/src/Components/Fieldset.php 的setUp()方法中调用了$this->columns(2)。此外make()的标签参数可以是string | Htmlable | Closure | null,支持闭包动态生成。渲染时,组件输出原生<fieldset>/<legend>结构(见Fieldset.php第 68-71 行),语义良好。

移除 Fieldset 边框

contained(false)去掉 fieldset 的容器边框:

use Filament\Schemas\Components\Fieldset; Fieldset::make('Label') ->contained(false) ->schema([ // ... ])

该能力来自Filament\Support\Concerns\CanBeContainedtrait(Fieldset.php第 17 行引入),渲染时通过fi-fieldset-not-containedCSS 类控制样式(见Fieldset.php第 64 行)。

控制组件间距

紧凑模式:dense()

dense()将组件间间距缩减 50%,创建更紧凑的布局:

use Filament\Schemas\Components\Fieldset; Fieldset::make('Dense') ->dense() ->schema([ // ... ])

去除间距:gap(false)

gap(false)完全移除组件间的间距:

use Filament\Schemas\Components\Fieldset; Fieldset::make('No gap') ->gap(false) ->schema([ // ... ])

两者的底层实现在 packages/schemas/src/Concerns/HasGap.php:dense()/gap()都接受布尔值或闭包;hasGap()isDense()具有继承语义——Schema会查询父组件的设置,组件则向容器逐级上溯(见第 23-31 行与第 42-51 行)。因此在一个 Section 上调用->dense(),其内部所有字段的间距都会收紧。

使用容器查询(Container Queries)

传统断点基于视口尺寸,而容器查询基于父容器的尺寸。当容器大小与视口无关时(例如内容区随可折叠侧栏动态伸缩),容器查询尤为有用。

第一步:指定容器。gridContainer()把元素标记为容器,其宽度决定布局:

use Filament\Schemas\Components\Grid; Grid::make() ->gridContainer() ->columns([ // ... ]) ->schema([ // ... ])

gridContainer()定义于 packages/schemas/src/Components/Concerns/CanBeGridContainer.php,默认值为false,可传闭包条件动态控制。

第二步:使用容器断点。标记为容器后,该元素及其子元素即可用容器断点替代标准断点——例如@md表示容器宽度至少 448px,@xl表示至少 576px:

use Filament\Schemas\Components\Grid; Grid::make() ->gridContainer() ->columns([ '@md' => 3, '@xl' => 4, ]) ->schema([ // ... ])

容器断点同样可用于columnSpan()columnStart()columnOrder()

use Filament\Forms\Components\TextInput; use Filament\Schemas\Components\Grid; Grid::make() ->gridContainer() ->columns([ '@md' => 3, '@xl' => 4, ]) ->schema([ TextInput::make('name') ->columnSpan([ '@md' => 2, '@xl' => 3, ]) ->columnOrder([ 'default' => 2, '@xl' => 1, ]), TextInput::make('email') ->columnSpan([ 'default' => 1, '@xl' => 1, ]) ->columnOrder([ 'default' => 1, '@xl' => 2, ]), // ... ])

本例中,容器宽度小于@xl(576px)时 email 在前、name 在后;宽度达到 576px 后顺序反转。

在旧浏览器上支持容器查询

容器查询的浏览器支持率不如传统断点。Filament 提供!@前缀的回退断点:当浏览器不支持容器查询时,自动应用回退值。例如栅格列数同时定义容器断点与回退断点:

use Filament\Schemas\Components\Grid; Grid::make() ->gridContainer() ->columns([ '@md' => 3, '@xl' => 4, '!@md' => 2, '!@xl' => 3, ]) ->schema([ // ... ])

!@回退断点也可用于columnSpan()columnStart()columnOrder()

use Filament\Forms\Components\TextInput; use Filament\Schemas\Components\Grid; Grid::make() ->gridContainer() ->columns([ '@md' => 3, '@xl' => 4, '!@md' => 2, '!@xl' => 3, ]) ->schema([ TextInput::make('name') ->columnSpan([ '@md' => 2, '@xl' => 3, '!@md' => 2, '!@xl' => 2, ]) ->columnOrder([ 'default' => 2, '@xl' => 1, '!@xl' => 1, ]), TextInput::make('email') ->columnOrder([ 'default' => 1, '@xl' => 2, '!@xl' => 2, ]), // ... ])

回退断点确保不支持容器查询的浏览器也能随视口尺寸响应,例如大屏下仍然保持 name 在前、email 在后。

延迟加载子 Schema

当布局包含渲染代价高昂的组件时,可向其schema()传入一个Schema对象并调用deferLoading()。子 schema 初始仅渲染一个加载指示器,待其进入视口后才真正加载:

use Filament\Forms\Components\TextInput; use Filament\Schemas\Components\Group; use Filament\Schemas\Schema; Group::make() ->key('customerDetails') ->schema( Schema::make() ->components([ TextInput::make('name'), TextInput::make('email') ->email(), ]) ->deferLoading(), )

本例使用Group(它自身没有任何视觉样式),其他接受子 schema 的布局组件亦可采用同样写法。每个延迟加载的 schema 必须有唯一 key:上例中它继承了带 key 的父组件customerDetails;也可以直接在子 schema 上调用key()。更多细节见 Schema 总览(如验证错误自动提前加载、隐藏组件内不加载、加载后保持存活等行为)。deferLoading()定义于 packages/schemas/src/Schema.php,接受布尔值或闭包条件。

给布局组件添加额外 HTML 属性

通过extraAttributes()向组件最外层 HTML 元素合并额外属性,以「属性名 => 属性值」数组形式传入:

use Filament\Schemas\Components\Section; Section::make() ->extraAttributes(['class' => 'custom-section-style'])

实现位于 packages/support/src/Concerns/HasExtraAttributes.php,签名默认extraAttributes(array | Closure $attributes, bool $merge = false)

  • 默认情况下,多次调用extraAttributes()覆盖之前的属性;
  • 若希望合并而非覆盖,传入merge: true
Section::make() ->extraAttributes(['class' => 'a'], merge: true) ->extraAttributes(['data-id' => '123'], merge: true)

该方法同样接受闭包,支持运行时动态计算与工具参数注入,常用于条件化样式、无障碍role/aria-*属性或自定义数据属性。

结语与延伸阅读

Filament 的布局体系以「所有布局组件支持columns()、所有组件支持columnSpan()」为核心,配合断点数组、闭包动态计算与容器查询,可在纯 PHP 声明式代码中构建完整、可复用的响应式界面,无需手写 CSS 与 JavaScript。相关主题可继续阅读:

  • Schema 总览(含组件工具注入与延迟加载详解)
  • Section 布局组件
  • Tabs 布局组件
  • Wizard 布局组件
  • Callout 布局组件
  • Empty state 布局组件
  • 自定义布局组件
  • 相关源码:HasColumns、HasGap、CanSpanColumns、CanOrderColumns、CanBeGridContainer
  • 相关测试:GridTest、FlexTest

【免费下载链接】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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询