资讯动态

Filament 资源页 Widget 集成实战:在 Resource 页面中展示与联动仪表盘组件

发布时间:2026/9/11 13:25:14 来源:尧图企业网站定制
Filament 资源页 Widget 集成实战在 Resource 页面中展示与联动仪表盘组件【免费下载链接】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 面板框架的资源Resource页面 Widget 能力展开你将学会如何通过make:filament-widget命令为某个资源创建专属 Widget如何把已有的仪表盘 Widget 挂载到 List / Edit / View 等资源页面的头部与底部并借助ExposesTableToWidgets与InteractsWithPageTable两个核心 Trait 让 Widget 与页面的表格、当前记录深度联动。读完即可在实战项目中构建“统计卡片 表格”的资源详情页与列表页。一、在资源页面中使用 Widget基本思路Filament 允许你在页面中展示 Widget位置在页面的头部header与底部footer之间header widgets渲染在页面内容上方适合放统计概览、图表等“概览型”信息footer widgets渲染在页面内容下方适合放补充说明、关联数据等。你可以直接复用已有的仪表盘 Widget如StatsOverviewWidget、ChartWidget、TableWidget也可以为某个资源单独创建一个专属 Widget。从源码看页面渲染 Widget 的逻辑集中在 Page.php 中headerWidgets()/footerWidgets()会分别用一个Grid布局容器把 Widget 包起来并在网格前后注入PanelsRenderHook::PAGE_HEADER_WIDGETS_START / END与PAGE_FOOTER_WIDGETS_START / END渲染钩子方便你进一步定制。二、创建资源专属 Widget为某个资源创建 Widget使用 Filament 提供的脚手架命令php artisan make:filament-widget CustomerOverview --resourceCustomerResource执行后会生成两个文件Widget 类位于app/Filament/Resources/Customers/Widgets目录Blade 视图位于resources/views/filament/resources/customers/widgets目录。从命令实现 MakeWidgetCommand.php 可以看到该命令的完整签名是make:filament-widget并带有两个别名filament:make-widget与filament:widget。除--resource别名-R外它还支持以下常用选项选项别名说明--resource-R指定所属资源Widget 会生成到该资源目录下的Widgets子目录--chart-C生成图表 WidgetChart Widget--stats-overview-S生成统计概览 WidgetStats Overview Widget--table-T生成表格 WidgetTable Widget--cluster—指定资源所属的 Cluster仅资源 Widget 有效--panel—指定 Widget 所在的 Panel--resource-namespace—资源类的命名空间默认如App\Filament\Resources--force-F若文件已存在则覆盖写入不指定--chart/--stats-overview/--table时命令会生成一个继承自Filament\Widgets\Widget的自定义 WidgetconfigureType()的默认分支见 MakeWidgetCommand.php。生成后你必须在新 Widget 的getWidgets()方法中注册它才能被资源感知到use App\Filament\Resources\Customers\Widgets\CustomerOverview; public static function getWidgets(): array { return [ CustomerOverview::class, ]; }getWidgets()的默认实现为空数组见 Resource.php返回类型为arrayclass-stringWidget即资源级注册的 Widget 类名列表。命令执行成功后终端也会提示你“请记得在getWidgets()中注册 Widget并将其添加到资源页面中”。关于 Widget 本身的构建与定制自定义视图、懒加载、列跨度等请参阅仪表盘 Widget 文档。需要说明的是Widget 本质上是一个独立的 Livewire 组件——基类 Widget.php 直接继承Livewire\Component并内置了CanAuthorizeAccess通过canView()控制可见性与CanBeLazy懒加载两个能力。三、在资源页面上展示 Widget资源页面如ListCustomers继承自ListRecords等内置页面类。要在页面上展示 Widget重写页面的getHeaderWidgets()或getFooterWidgets()方法?php namespace App\Filament\Resources\Customers\Pages; use App\Filament\Resources\Customers\CustomerResource; class ListCustomers extends ListRecords { public static string $resource CustomerResource::class; protected function getHeaderWidgets(): array { return [ CustomerResource\Widgets\CustomerOverview::class, ]; } }其中getHeaderWidgets()返回要在页面内容上方展示的 Widget 数组getFooterWidgets()返回要在页面内容下方展示的 Widget 数组。两个方法的默认实现均为空数组见 Page.php 与 Page.php返回元素可以是 Widget 类名也可以是WidgetConfiguration实例见下文“向 Widget 传递属性”。自定义 Widget 网格列数Widget 默认在每行 2 列的网格中排列getHeaderWidgetsColumns()与getFooterWidgetsColumns()默认都返回2见 Page.php 与 Page.php。你可以通过覆写这两个方法来调整列数public function getHeaderWidgetsColumns(): int | array { return 3; }甚至可以根据响应式断点返回数组让不同屏幕宽度使用不同的列数public function getHeaderWidgetsColumns(): int | array { return [ md 4, xl 5, ]; }这与自定义页面文档中介绍的机制完全一致可以配合响应式 Widget 宽度基于columnSpan/columnStart属性实现精细的栅格布局。页面如何把 Widget 渲染出去从底层实现看页面并非直接在 Blade 中硬编码 Widget而是通过getWidgetsSchemaComponents()把 Widget 数组转换为 Schema 组件见 Page.php。该过程中有两个值得注意的细节可见性过滤每个 Widget 都会经过canView()检查不可见的 Widget 会被自动过滤掉无需手动处理权限逻辑数据注入每个 Widget 都会收到页面的getWidgetData()数据、make()传入的属性以及getDefaultProperties()如懒加载标志的合并结果并通过Livewire::make(...)以唯一 key 挂载。这也解释了为什么在资源页面上注册的 Widget 能自动感知页面状态——数据链路在渲染阶段就已打通。四、在 Widget 中访问当前记录Edit / View 页面如果你的 Widget 被用在资源的Edit编辑或View查看页面上并且需要访问当前正在编辑/查看的记录只需在 Widget 类中声明一个$record公共属性use Illuminate\Database\Eloquent\Model; public ?Model $record null;页面框架会自动把当前记录注入到这个属性中。之后你就可以在 Widget 的getStats()、getData()或 Blade 视图中通过$this-record读取该 Eloquent 模型例如展示订单金额、用户等级等与该记录强相关的统计信息。相关页面行为可参考编辑记录与查看记录文档。五、在 Widget 中访问页面表格数据List 页面如果你想把 Widget 用在资源的List列表页面上并希望 Widget 直接读取表格的查询结果如“当前筛选条件下的记录数”“当前页记录集合”需要分别在页面与 Widget 两侧各加一个 Trait。第一步页面侧暴露表格数据在 List 页面类上引入ExposesTableToWidgetsTraituse Filament\Pages\Concerns\ExposesTableToWidgets; use Filament\Resources\Pages\ListRecords; class ListProducts extends ListRecords { use ExposesTableToWidgets; // ... }该 Trait 的实现见 ExposesTableToWidgets.php它通过getWidgetData()方法把页面表格的完整“活状态”打包成数组activeTab当前激活的表格 Tabpaginators分页状态parentRecord父级记录用于嵌套资源tableColumnSearches列搜索关键词tableFilters当前应用的表格筛选器tableGrouping当前分组方式tableRecordsCount全部记录的计数来自getAllTableRecordsCount()tableRecordsPerPage每页记录数tableSearch全局搜索关键词tableSort当前排序字段。也就是说页面的搜索、筛选、分页、排序等状态都会随 Widget 渲染一并传递给挂载的 Widget。第二步Widget 侧接入页面表格在 Widget 类上引入InteractsWithPageTableTrait并覆写getTablePage()返回页面类名use App\Filament\Resources\Products\Pages\ListProducts; use Filament\Widgets\Concerns\InteractsWithPageTable; use Filament\Widgets\Widget; class ProductStats extends Widget { use InteractsWithPageTable; protected function getTablePage(): string { return ListProducts::class; } // ... }该 Trait 的实现见 InteractsWithPageTable.php其工作方式如下声明与页面同步的#[Reactive]公共属性paginators、tableRecordsCount、tableColumnSearches、tableGrouping、tableFilters、tableRecordsPerPage、tableSearch、tableSort、activeTab、parentRecord等。借助 Livewire 的响应式属性机制当用户在页面上切换筛选、翻页、搜索时Widget 会自动收到最新状态并重新计算——这是“Widget 与表格保持同步”的关键所在。getTablePageInstance()按需实例化目标页面组件并触发其mount把上述状态回填进去再调用bootedInteractsWithTable()从而获得一个与真实页面等价的表格实例结果会缓存复用。getPageTableQuery()返回getFilteredSortedTableQuery()的结果即经过筛选与排序后的 Eloquent 查询构造器getPageTableRecords()返回getTableRecords()的结果即当前页的记录集合分页后。如果在 Widget 中未定义getTablePage()Trait 会抛出LogicException提示你必须返回一个 Livewire 组件的类名见 InteractsWithPageTable.php。使用表格查询在 Widget 中用getPageTableQuery()拿到查询构造器后即可基于当前筛选条件做任意聚合统计use Filament\Widgets\StatsOverviewWidget\Stat; Stat::make(Total Products, $this-getPageTableQuery()-count()),这样做的好处是统计值会跟随用户在表格上的筛选、搜索、排序实时变化例如“筛选出价格为空的商品后总数卡片立即更新”。使用当前页记录如果你只想统计当前页而非全部筛选结果的记录可以使用getPageTableRecords()use Filament\Widgets\StatsOverviewWidget\Stat; Stat::make(Total Products, $this-getPageTableRecords()-count()),该方法返回Collection | Paginator——当表格启用分页时返回分页器否则返回 Eloquent 集合可直接遍历或count()。六、直接获取表格总记录数如果你需要的是“该表格查询的全部记录总数”但又不想额外执行一次 count 查询可以直接使用 Trait 提供的$tableRecordsCount属性use Filament\Widgets\StatsOverviewWidget\Stat; Stat::make(Total Products, $this-tableRecordsCount),该属性在 InteractsWithPageTable.php 中被声明为#[Reactive] public ?int $tableRecordsCount null;其数据来源是页面侧ExposesTableToWidgets::getWidgetData()中的getAllTableRecordsCount()——即忽略分页、只考虑搜索与筛选的全量计数且复用页面已有的查询结果不会产生重复查询开销。七、向资源页面上的 Widget 传递属性在页面上注册 Widget 时可以通过make()方法向它传递一组 Livewire 属性protected function getHeaderWidgets(): array { return [ CustomerResource\Widgets\CustomerOverview::make([ status active, ]), ]; }这组属性会被映射为 Widget 类上的公共 Livewire 属性use Filament\Widgets\Widget; class CustomerOverview extends Widget { public string $status; // ... }之后你就可以在 Widget 类中使用$this-status读取该值实现“同一个 Widget 在不同页面以不同参数复用”的效果。从源码看make()的签名是Widget::make(array $properties [])返回的是一个WidgetConfiguration实例见 Widget.php 与 WidgetConfiguration.php内部仅保存 Widget 类名与属性数组。页面在渲染时会通过getWidgetsSchemaComponents()把WidgetConfiguration中的属性合并getDefaultProperties()后注入 Livewire 组件见 Page.php。页面级数据透传getWidgetData()除了用make()按 Widget 传参页面还支持通过getWidgetData()向所有挂载的 Widget 批量透传数据机制见自定义页面文档public function getWidgetData(): array { return [ stats [ total 100, ], ]; }对应的 Widget 上声明同名公共属性即可自动接收public $stats [];注意资源页面默认的getWidgetData()返回空数组见 Page.php而ExposesTableToWidgets会覆盖它来提供表格状态这两种机制可以共存它们最终会与make()属性合并后一起注入 Widget。八、完整示例一个联动表格的统计头部把以上能力组合起来一个典型的“列表页 统计卡片头部”完整实现如下。Widget 类app/Filament/Resources/Products/Widgets/ProductStats.php?php namespace App\Filament\Resources\Products\Widgets; use App\Filament\Resources\Products\Pages\ListProducts; use Filament\Widgets\Concerns\InteractsWithPageTable; use Filament\Widgets\StatsOverviewWidget; use Filament\Widgets\StatsOverviewWidget\Stat; class ProductStats extends StatsOverviewWidget { use InteractsWithPageTable; protected function getTablePage(): string { return ListProducts::class; } protected function getStats(): array { return [ Stat::make(Total Products, $this-tableRecordsCount), Stat::make(Filtered Products, $this-getPageTableQuery()-count()), ]; } }List 页面app/Filament/Resources/Products/Pages/ListProducts.php?php namespace App\Filament\Resources\Products\Pages; use App\Filament\Resources\Products\ProductResource; use App\Filament\Resources\Products\Widgets\ProductStats; use Filament\Pages\Concerns\ExposesTableToWidgets; use Filament\Resources\Pages\ListRecords; class ListProducts extends ListRecords { use ExposesTableToWidgets; public static string $resource ProductResource::class; protected function getHeaderWidgets(): array { return [ ProductStats::class, ]; } }这样列表页头部会渲染两张统计卡片Total Products显示全部商品数Filtered Products则随用户的搜索与筛选实时变化。配合 Stat 组件的description()、color()、icon()等方法即可快速搭建具备运营价值的资源页概览区。九、小结与更多参考资源页 Widget 的核心脉络可以概括为三条链路创建与注册make:filament-widget --resource...生成类与视图 → 在资源的getWidgets()中注册 → 在页面的getHeaderWidgets()/getFooterWidgets()中挂载记录联动Edit / View 页面通过$record属性把当前模型注入 Widget表格联动List 页面通过ExposesTableToWidgetsInteractsWithPageTable把搜索、筛选、分页、排序状态同步给 Widget并通过getPageTableQuery()/getPageTableRecords()/$tableRecordsCount提供三种粒度的数据访问方式。继续深入可参考以下仓库资源Widget 基类与 make() 属性注入页面表格数据暴露 TraitWidget 与页面表格交互 Trait页面 Widget 渲染与网格逻辑make:filament-widget 命令实现自定义页面中的 Widget 与响应式网格仪表盘 Widget 构建指南列表记录页面、编辑记录页面、查看记录页面【免费下载链接】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),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价