概述
简介
若要为应用添加第二层导航,可以使用 集群。它们适合将资源和页面分组到一起。
自定义导航项标签
默认情况下,导航标签根据资源或页面的名称生成。你可以使用 $navigationLabel 属性自定义:
protected static ?string $navigationLabel = 'Custom Navigation Label';或者,你可以覆盖 getNavigationLabel() 方法:
public static function getNavigationLabel(): string
{
return 'Custom Navigation Label';
}自定义导航项图标
use BackedEnum;
use Filament\Support\Icons\Heroicon;
protected static string | BackedEnum | null $navigationIcon = Heroicon::OutlinedDocumentText;

若将同一导航分组内所有项的 $navigationIcon = null,这些项会在分组标签下方用竖线连接。
在导航项激活时切换图标
你可以使用 $activeNavigationIcon 属性指定仅用于激活项的导航 图标:
use BackedEnum;
use Filament\Support\Icons\Heroicon;
protected static string | BackedEnum | null $activeNavigationIcon = Heroicon::OutlinedDocumentText;

排序导航项
默认情况下,导航项按字母顺序排序。你可以使用 $navigationSort 属性自定义:
protected static ?int $navigationSort = 3;现在,排序值较小的导航项会出现在排序值较大的项之前——顺序为升序。


为导航项添加徽章
若要在导航项旁添加徽章,可以使用 getNavigationBadge() 方法并返回徽章内容:
public static function getNavigationBadge(): ?string
{
return static::getModel()::count();
}

若 getNavigationBadge() 返回了徽章值,默认会使用 primary 颜色显示。若要按语境为徽章设置样式,请从 getNavigationBadgeColor() 方法返回 danger、gray、info、primary、success 或 warning:
public static function getNavigationBadgeColor(): ?string
{
return static::getModel()::count() > 10 ? 'warning' : 'primary';
}

可以在 $navigationBadgeTooltip 中设置导航徽章的自定义提示:
protected static ?string $navigationBadgeTooltip = 'The number of users';或者从 getNavigationBadgeTooltip() 返回:
public static function getNavigationBadgeTooltip(): ?string
{
return 'The number of users';
}

分组导航项
use UnitEnum;
protected static string | UnitEnum | null $navigationGroup = 'Settings';

同一导航分组中的所有项会一起显示在相同的分组标签下,本例中为「Settings」。未分组的项会留在导航的起始位置。
将导航项分组到其他项下
你可以通过设置 $navigationParentItem 属性,将导航项作为其他项的子项进行分组。可以通过父项的页面或资源类,或通过其标签来引用父项:
use App\Filament\Resources\Notifications\NotificationResource;
use UnitEnum;
protected static ?string $navigationParentItem = NotificationResource::class;
protected static string | UnitEnum | null $navigationGroup = 'Settings';或者,你可以通过标签引用父项:
use UnitEnum;
protected static ?string $navigationParentItem = 'Notifications';
protected static string | UnitEnum | null $navigationGroup = 'Settings';你也可以使用 getNavigationParentItem() 方法动态确定父项:
use App\Filament\Resources\Notifications\NotificationResource;
public static function getNavigationParentItem(): ?string
{
return NotificationResource::class;
}或者,你可以返回父项的标签:
public static function getNavigationParentItem(): ?string
{
return __('filament/navigation.groups.settings.items.notifications');
}父项和子项必须属于同一导航分组。若父项有导航分组,子项也必须定义该分组,否则无法识别正确的父项。无论通过类还是标签引用父项,都适用此规则。
TIP
若你正在考虑这样的第三层导航,应改用 集群。集群是资源和自定义页面的逻辑分组,可以共享各自独立的导航。
自定义导航分组
你可以在 配置 中调用 navigationGroups(),并按顺序传入 NavigationGroup 对象来自定义导航分组:
use Filament\Navigation\NavigationGroup;
use Filament\Panel;
use Filament\Support\Icons\Heroicon;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->navigationGroups([
NavigationGroup::make()
->label('Shop')
->icon(Heroicon::OutlinedShoppingCart),
NavigationGroup::make()
->label('Blog')
->icon(Heroicon::OutlinedPencil),
NavigationGroup::make()
->label(fn (): string => __('navigation.settings'))
->icon(Heroicon::OutlinedCog6Tooth)
->collapsed(),
]);
}本例中,我们为分组传入自定义 icon(),并让其中一个默认 collapsed()。
排序导航分组
使用 navigationGroups() 时,你是在为导航分组定义新顺序。若只想重新排序分组而不定义完整的 NavigationGroup 对象,只需按新顺序传入分组的标签:
$panel
->navigationGroups([
'Shop',
'Blog',
'Settings',
])使导航分组不可折叠
默认情况下,导航分组是可折叠的。


你可以在 NavigationGroup 对象上调用 collapsible(false) 来禁用此行为:
use Filament\Navigation\NavigationGroup;
use Filament\Support\Icons\Heroicon;
NavigationGroup::make()
->label('Settings')
->icon(Heroicon::OutlinedCog6Tooth)
->collapsible(false);

或者,可以在 配置 中为所有分组全局设置:
use Filament\Panel;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->collapsibleNavigationGroups(false);
}为导航分组添加额外 HTML 属性
你可以为导航分组传入额外 HTML 属性,它们会合并到外层 DOM 元素上。将属性数组传给 extraSidebarAttributes() 或 extraTopbarAttributes() 方法,键为属性名,值为属性值:
NavigationGroup::make()
->extraSidebarAttributes(['class' => 'featured-sidebar-group']),
->extraTopbarAttributes(['class' => 'featured-topbar-group']),extraSidebarAttributes() 会应用于侧栏中的导航分组元素,extraTopbarAttributes() 仅在使用 顶部导航 时应用于顶栏导航分组下拉菜单。
使用枚举注册导航分组
你可以使用枚举类注册导航分组,从而在单一位置控制它们的标签、图标和顺序,而无需在 配置 中注册。
为此,可以创建一个包含每个分组 case 的枚举类:
enum NavigationGroup
{
case Shop;
case Blog;
case Settings;
}case 的定义顺序会控制导航分组的顺序。
要为资源或自定义页面使用枚举导航分组,可以将 $navigationGroup 属性设为枚举 case:
protected static string | UnitEnum | null $navigationGroup = NavigationGroup::Shop;你也可以在枚举类上实现 HasLabel 接口,为每个分组定义自定义标签:
use Filament\Support\Contracts\HasLabel;
enum NavigationGroup implements HasLabel
{
case Shop;
case Blog;
case Settings;
public function getLabel(): string
{
return match ($this) {
self::Shop => __('navigation-groups.shop'),
self::Blog => __('navigation-groups.blog'),
self::Settings => __('navigation-groups.settings'),
};
}
}你也可以在枚举类上实现 HasIcon 接口,为每个分组定义自定义图标:
use BackedEnum;
use Filament\Support\Contracts\HasIcon;
use Filament\Support\Icons\Heroicon;
use Illuminate\Contracts\Support\Htmlable;
enum NavigationGroup implements HasIcon
{
case Shop;
case Blog;
case Settings;
public function getIcon(): string | BackedEnum | Htmlable | null
{
return match ($this) {
self::Shop => Heroicon::OutlinedShoppingCart,
self::Blog => Heroicon::OutlinedPencil,
self::Settings => Heroicon::OutlinedCog6Tooth,
};
}
}桌面端可折叠侧栏
若要让侧栏在桌面端和移动端都可折叠,可以使用 配置:
use Filament\Panel;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->sidebarCollapsibleOnDesktop();
}

默认情况下,在桌面端折叠侧栏时仍会显示导航图标。你可以使用 sidebarFullyCollapsibleOnDesktop() 方法完全折叠侧栏:
use Filament\Panel;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->sidebarFullyCollapsibleOnDesktop();
}

桌面端可折叠侧栏中的导航分组
INFO
本节仅适用于 sidebarCollapsibleOnDesktop(),不适用于 sidebarFullyCollapsibleOnDesktop(),因为完全折叠的 UI 只是隐藏整个侧栏,而不是改变其设计。
在桌面端使用可折叠侧栏时,通常也会使用 导航分组。默认情况下,侧栏折叠时每个导航分组的标签会被隐藏,因为没有空间显示它们。即使导航分组本身是 可折叠的,折叠侧栏中仍会显示所有项,因为没有可点击以展开分组的分组标签。
这些问题可以通过向导航分组对象 传入 icon() 来解决,从而实现非常精简的侧栏设计。定义图标后,折叠侧栏会始终显示图标而不是各项。点击图标时,会在图标旁打开下拉菜单,显示分组中的项。
向导航分组传入图标时,即使各项也有图标,展开的侧栏 UI 也不会显示项图标。这是为了保持导航层级清晰、设计精简。不过,折叠侧栏的下拉菜单中会显示各项的图标,因为下拉菜单已打开,层级已经清晰。


注册自定义导航项
若要注册新的导航项,可以使用 配置:
use Filament\Navigation\NavigationItem;
use Filament\Pages\Dashboard;
use Filament\Panel;
use Filament\Support\Icons\Heroicon;
use function Filament\Support\original_request;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->navigationItems([
NavigationItem::make('Analytics')
->url('https://filament.pirsch.io', shouldOpenInNewTab: true)
->icon(Heroicon::OutlinedPresentationChartLine)
->group('Reports')
->sort(3),
NavigationItem::make('dashboard')
->label(fn (): string => __('filament-panels::pages/dashboard.title'))
->url(fn (): string => Dashboard::getUrl())
->isActiveWhen(fn () => original_request()->routeIs('filament.admin.pages.dashboard')),
// ...
]);
}有条件地隐藏导航项
你也可以使用 visible() 或 hidden() 方法,并传入要检查的条件,有条件地隐藏导航项:
use Filament\Navigation\NavigationItem;
NavigationItem::make('Analytics')
->visible(fn(): bool => auth()->user()->can('view-analytics'))
// or
->hidden(fn(): bool => ! auth()->user()->can('view-analytics')),禁用资源或页面导航项
若要阻止资源或页面出现在导航中,可以使用:
protected static bool $shouldRegisterNavigation = false;或者,你可以覆盖 shouldRegisterNavigation() 方法:
public static function shouldRegisterNavigation(): bool
{
return false;
}使用顶部导航
默认情况下,Filament 使用侧栏导航。你可以通过 配置 改用顶部导航:
use Filament\Panel;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->topNavigation();
}

自定义侧栏宽度
你可以通过在 配置 中将宽度传给 sidebarWidth() 方法来自定义侧栏宽度:
use Filament\Panel;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->sidebarWidth('40rem');
}

此外,若使用了 sidebarCollapsibleOnDesktop() 方法,可以通过 配置 中的 collapsedSidebarWidth() 方法自定义折叠后图标区域的宽度:
use Filament\Panel;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->sidebarCollapsibleOnDesktop()
->collapsedSidebarWidth('9rem');
}高级导航自定义
可以在 配置 中调用 navigation() 方法。它允许你构建自定义导航,覆盖 Filament 自动生成的项。此 API 旨在让你完全控制导航。
注册自定义导航项
若要注册导航项,请调用 items() 方法:
use App\Filament\Pages\Settings;
use App\Filament\Resources\Users\UserResource;
use Filament\Navigation\NavigationBuilder;
use Filament\Navigation\NavigationItem;
use Filament\Pages\Dashboard;
use Filament\Panel;
use Filament\Support\Icons\Heroicon;
use function Filament\Support\original_request;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->navigation(function (NavigationBuilder $builder): NavigationBuilder {
return $builder->items([
NavigationItem::make('Dashboard')
->icon(Heroicon::OutlinedHome)
->isActiveWhen(fn (): bool => original_request()->routeIs('filament.admin.pages.dashboard'))
->url(fn (): string => Dashboard::getUrl()),
...UserResource::getNavigationItems(),
...Settings::getNavigationItems(),
]);
});
}

注册自定义导航分组
若要注册分组,可以调用 groups() 方法:
use App\Filament\Pages\HomePageSettings;
use App\Filament\Resources\Categories\CategoryResource;
use App\Filament\Resources\Pages\PageResource;
use Filament\Navigation\NavigationBuilder;
use Filament\Navigation\NavigationGroup;
use Filament\Panel;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->navigation(function (NavigationBuilder $builder): NavigationBuilder {
return $builder->groups([
NavigationGroup::make('Website')
->items([
...PageResource::getNavigationItems(),
...CategoryResource::getNavigationItems(),
...HomePageSettings::getNavigationItems(),
]),
]);
});
}禁用导航
你可以通过向 navigation() 方法传入 false 来完全禁用导航:
use Filament\Panel;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->navigation(false);
}

或者,你可以传入返回布尔值的闭包来动态决定。返回 false 会隐藏导航,返回 true 则渲染默认自动发现的导航项。这适用于引导或设置向导等流程,导航应仅在用户到达特定状态后出现:
use Filament\Panel;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->navigation(fn (): bool => auth()->user()->hasCompletedOnboarding());
}禁用顶栏
你可以通过向 topbar() 方法传入 false 来完全禁用顶栏:
use Filament\Panel;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->topbar(false);
}替换侧栏和顶栏 Livewire 组件
你可以完全替换用于渲染侧栏和顶栏的 Livewire 组件,将自己的 Livewire 组件类名传给 sidebarLivewireComponent() 或 topbarLivewireComponent() 方法:
use App\Livewire\Sidebar;
use App\Livewire\Topbar;
use Filament\Panel;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->sidebarLivewireComponent(Sidebar::class)
->topbarLivewireComponent(Topbar::class);
}禁用面包屑
默认布局会显示面包屑,以指示当前页面在应用层级中的位置。
你可以在 配置 中禁用面包屑:
use Filament\Panel;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->breadcrumbs(false);
}重新加载侧栏和顶栏
面板中的页面加载后,侧栏和顶栏在你离开该页面,或点击菜单项触发操作之前不会重新加载。你可以通过派发 refresh-sidebar 或 refresh-topbar 浏览器事件来手动重新加载这些组件以更新它们。
若要从 PHP 派发事件,可以从任何 Livewire 组件(如页面类、关系管理器类或小部件类)调用 $this->dispatch() 方法:
$this->dispatch('refresh-sidebar');当你的代码不在 Livewire 组件内时(例如自定义操作类),可以向闭包函数注入 $livewire 参数,并在其上调用 dispatch():
use Filament\Actions\Action;
use Livewire\Component;
Action::make('create')
->action(function (Component $livewire) {
// ...
$livewire->dispatch('refresh-sidebar');
})或者,你可以使用 $dispatch() Alpine.js 辅助方法,或原生浏览器的 window.dispatchEvent() 方法从 JavaScript 派发事件:
<button x-on:click="$dispatch('refresh-sidebar')" type="button">
Refresh Sidebar
</button>window.dispatchEvent(new CustomEvent('refresh-sidebar'));