布局
简介
Filament 的网格系统允许你使用任意布局组件创建响应式多列布局。Filament 提供一组内置布局组件来帮助你构建:
你也可以 创建自己的自定义布局组件,按任意方式展示组件。
网格系统
所有布局组件都有 columns() 方法,可用几种不同方式使用:
- 可传入整数,如 `columns(2)`。该整数是 `lg` 断点及以上使用的列数。更小的设备将只有 1 列。
- 可传入数组,键为断点,值为列数。例如,`columns(['md' => 2, 'xl' => 4])` 会在中等设备上创建 2 列布局,在超大设备上创建 4 列布局。更小设备的默认断点使用 1 列,除非使用 `default` 数组键。
断点(sm、md、lg、xl、2xl)由 Tailwind 定义,详见 Tailwind 文档。
TIP
除了接受静态值外,columns() 方法也接受函数以动态计算。你可以将各种工具作为参数注入该函数。
网格列跨度
除了指定布局组件应有多少列外,还可使用 columnSpan() 方法指定组件在父网格中应占多少列。该方法接受整数,或断点与列跨度的数组:
- 可传入整数,如 `columnSpan(2)`。该整数是 `lg` 断点及以上占用的列数。更小的设备仅跨 1 列。
- `columnSpan(['md' => 2, 'xl' => 4])` 会使组件在中等设备上最多占 2 列,在超大设备上最多占 4 列。更小设备的默认断点使用 1 列,除非使用 `default` 数组键。
- `columnSpan('full')` 会使组件在 `lg` 断点及以上占满父网格全宽,无论有多少列。更小的设备仅跨 1 列。
- `columnSpanFull()` 会使组件在所有设备上占满父网格全宽,无论有多少列。
TIP
除了接受静态值外,columnSpan() 方法也接受函数以动态计算。你可以将各种工具作为参数注入该函数。


网格列起始位置
若希望组件在网格中从特定列开始,可使用 columnStart() 方法。该方法接受整数,或断点与起始列的数组:
- 可传入整数,如 `columnStart(2)`。该整数是组件在 `lg` 断点及以上的起始列。更小的设备从第一列开始。
- `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 列开始。这本质上产生一种布局:无论网格有多少列,文本输入总是从网格中部开始。
TIP
除了接受静态值外,columnStart() 方法也接受函数以动态计算。你可以将各种工具作为参数注入该函数。


网格列排序
若希望在不改变标记中位置的情况下控制网格中组件的视觉顺序,可使用 columnOrder() 方法。该方法接受整数、闭包,或断点与顺序值的数组:
- 可传入整数,如 `columnOrder(2)`。该整数是组件在 `lg` 断点及以上的出现顺序。更小的设备使用默认顺序,除非使用 `default` 数组键。
- `columnOrder(['md' => 2, 'xl' => 4])` 会将组件顺序在中等设备上设为 2,在超大设备上设为 4。更小设备的默认断点使用默认顺序,除非使用 `default` 数组键。
- `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。
TIP
除了接受静态值外,columnOrder() 方法也接受函数以动态计算。你可以将各种工具作为参数注入该函数。
响应式网格布局示例
本例中,我们有一个带 分区 布局组件的 schema。由于所有布局组件都支持 columns() 方法,可用它在分区本身内创建响应式网格布局。
我们向 columns() 传入数组,因为要为不同断点指定不同列数。小于 sm Tailwind 断点 的设备使用默认的 1 列。大于 sm 断点的设备使用 3 列。大于 xl 断点的设备使用 6 列。大于 2xl 断点的设备使用 8 列。
分区内有一个 文本输入。由于文本输入是表单字段且所有组件都有 columnSpan() 方法,可用它指定文本输入应占多少列。小于 sm 断点的设备使用默认的 1 列。大于 sm 断点占 2 列,大于 xl 断点占 3 列,大于 2xl 断点占 4 列。
此外,我们使用 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,
]),
// ...
])本例中,小于 xl 断点的屏幕上,email 字段先出现,然后是 name 字段。大于 xl 断点的屏幕上顺序相反:name 字段先出现,然后是 email 字段。
基础布局组件
Grid 组件
所有布局组件都支持 columns() 方法,此外还可使用 Grid 组件。若希望 schema 使用无额外样式的显式网格语法,它会很有用。可不使用 columns() 方法,而将列配置直接传给 Grid::make():
use Filament\Schemas\Components\Grid;
Grid::make([
'default' => 1,
'sm' => 2,
'md' => 3,
'lg' => 4,
'xl' => 6,
'2xl' => 8,
])
->schema([
// ...
])

Flex 组件
Flex 组件允许你使用 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')本例中,第一个分区会 grow() 以占用可用水平空间,而不影响渲染第二个分区所需的空间。这会产生弹性宽度侧边栏效果。
from() 方法用于控制应使用水平分割布局的 Tailwind 断点(sm、md、lg、xl、2xl)。本例中,中等及以上设备使用水平分割布局。更小的设备上,分区会上下堆叠。
TIP
除了接受静态值外,grow() 与 from() 方法也接受函数以动态计算。你可以将各种工具作为参数注入这些函数。


Fieldset 组件
你可能希望将字段分组到 Fieldset 中。每个 fieldset 默认有标签、边框和两列网格:
use Filament\Schemas\Components\Fieldset;
Fieldset::make('Label')
->columns([
'default' => 1,
'md' => 2,
'xl' => 3,
])
->schema([
// ...
])TIP
除了接受静态标签外,make() 方法也接受函数以动态计算。你可以将各种工具作为参数注入该函数。


移除 fieldset 边框
可使用 contained(false) 方法移除 fieldset 的容器边框:
use Filament\Schemas\Components\Fieldset;
Fieldset::make('Label')
->contained(false)
->schema([
// ...
])TIP
除了接受静态值外,contained() 方法也接受函数以动态计算。你可以将各种工具作为参数注入该函数。


控制组件间距
减小组件间距
dense() 方法通过将组件间距减小 50% 来创建更紧凑的布局:
use Filament\Schemas\Components\Fieldset;
Fieldset::make('Dense')
->dense()
->schema([
// ...
])

移除组件间距
gap(false) 方法移除组件之间的间距:
use Filament\Schemas\Components\Fieldset;
Fieldset::make('No gap')
->gap(false)
->schema([
// ...
])

使用容器查询
除了基于视口尺寸的传统断点外,还可使用 容器查询 根据父容器尺寸创建响应式布局。当父容器尺寸与视口尺寸不直接相关时尤其有用。例如,在内容旁使用可折叠侧边栏时,内容区域会根据侧边栏折叠状态动态调整大小。
容器查询的基础是容器本身。容器是其宽度决定布局的元素。要将元素指定为容器,对其使用 gridContainer() 方法。例如,若要根据 Grid 组件 的宽度定义网格列数:
use Filament\Schemas\Components\Grid;
Grid::make()
->gridContainer()
->columns([
// ...
])
->schema([
// ...
])一旦元素被指定为网格容器,该元素或其任意子元素都可使用 容器断点 而非标准断点。例如,可用 @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 时,顺序相反:name 字段先出现,然后是 email 字段。
在旧版浏览器上支持容器查询
与传统断点相比,容器查询尚未被浏览器广泛 支持。为支持旧版浏览器,可在容器断点旁定义额外一层断点。通过在传统断点前加上 !@ 前缀,可指定在浏览器不支持容器查询时使用回退断点。
例如,若要对网格列使用 @md 容器断点同时又支持旧版浏览器,可定义 !@md 回退断点,在容器查询不可用时应用:
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 的父组件继承。更多信息见 schema 概览。
为布局组件添加额外 HTML 属性
可通过 extraAttributes() 方法向组件传入额外 HTML 属性,它们会合并到其外层 HTML 元素上。属性应以数组表示,键为属性名,值为属性值:
use Filament\Schemas\Components\Section;
Section::make()
->extraAttributes(['class' => 'custom-section-style'])TIP
除了接受静态值外,extraAttributes() 方法也接受函数以动态计算。你可以将各种工具作为参数注入该函数。
默认情况下,多次调用 extraAttributes() 会覆盖先前的属性。若希望合并属性,可向该方法传入 merge: true。