Languages

Version

Theme

导航栏

概述

简介

默认情况下,Filament 将为每个资源自定义页面Clusters 注册导航项目。这些类都包含一些静态属性和方法,你可以重写配置导航项目。

如果你想在应道的导航中添加第二层导航,可以使用 Clusters。这对于将资源和页面分组到一起很有用。

自定义导航项标签

默认情况下,导航标签是由资源或者页面名称生成。你可以使用 $navigationLabel 属性自定义:

protected static ?string $navigationLabel = 'Custom Navigation Label';

此外,你也可以自定义 getNavigationLabel() 方法:

public static function getNavigationLabel(): string
{
    return 'Custom Navigation Label';
}

自定义导航项图标

要自定义导航项的图标,你可以重写资源页面类的 $navigationIcon 属性:

use BackedEnum;

protected static string | BackedEnum | null $navigationIcon = 'heroicon-o-document-text';
Changed navigation item icon

如果你将同一导航分组内的所有项目都设置 $navigationIcon = null,则这些项目将通过分组标签下方的垂直条连接起来。

当导航项激活时切换图标

通过 $activeNavigationIcon 属性,你指定一个仅用于导航项激活时的图标

protected static ?string $activeNavigationIcon = 'heroicon-o-document-text';
Different navigation item icon when active

导航项排序

默认情况下,导航项按照字母顺序排序。你可以使用 $navigationSort 属性自定义排序:

protected static ?int $navigationSort = 3;

排序值较低的导航项会排在排序值高的项目之前,排序顺序为升序。

Sort navigation items

添加徽章到导航项中

要在导航项旁添加徽章,你可以使用 getNavigationBadge() 方法并返回徽章内容:

public static function getNavigationBadge(): ?string
{
    return static::getModel()::count();
}
Navigation item with badge

如果 getNavigationBadge() 返回徽章值,则默认情况下将使用 primary 颜色显示。要根据上下文设置徽章样式,请在 getNavigationBadgeColor() 方法返回 dangergrayinfoprimary successwarning

public static function getNavigationBadgeColor(): ?string
{
    return static::getModel()::count() > 10 ? 'warning' : 'primary';
}
Navigation item with badge color

导航徽章的自定义 tooltip 提示可以在 $navigationBadgeTooltip 中进行设置:

protected static ?string $navigationBadgeTooltip = 'The number of users';

或者也可以由 getNavigationBadgeTooltip() 返回:

public static function getNavigationBadgeTooltip(): ?string
{
    return 'The number of users';
}
Navigation item with badge tooltip

导航项分组

通过指定资源自定义页面中的 $navigationGroup 属性,你可以对导航项进行分组:

use UnitEnum;

protected static string | UnitEnum | null $navigationGroup = 'Settings';
Grouped navigation items

处于同一个分组的项目将会展示在同一个分组标签之下,比如上例中的 Settings。未分组项将保留在导航的起始位置。.

在其他项目之下分组导航项

将父项标签传入到 $navigationParentItem 中,你可以将导航项作为其他项目的子项:

use UnitEnum;

protected static ?string $navigationParentItem = 'Notifications';

protected static string | UnitEnum | null $navigationGroup = 'Settings';

你也可以使用 getNavigationParentItem() 动态设置父项标签:

public static function getNavigationParentItem(): ?string
{
    return __('filament/navigation.groups.settings.items.notifications');
}

如上所示,如果父项有导航分组,就必须定义导航分组,这样磁能正确识别父项。

TIP

如果你寻找类似的第三级导航分组,则可以考虑 Clusters,它是资源和自定义页面的逻辑分组,可以共享自己的单独导航。

自定义导航分组

配置中调用 navigationGroups() 并按照顺序传入 NavigationGroup 对象,你可以自定义导航分组:

use Filament\Navigation\NavigationGroup;
use Filament\Panel;

public function panel(Panel $panel): Panel
{
    return $panel
        // ...
        ->navigationGroups([
            NavigationGroup::make()
                 ->label('Shop')
                 ->icon('heroicon-o-shopping-cart'),
            NavigationGroup::make()
                ->label('Blog')
                ->icon('heroicon-o-pencil'),
            NavigationGroup::make()
                ->label(fn (): string => __('navigation.settings'))
                ->icon('heroicon-o-cog-6-tooth')
                ->collapsed(),
        ]);
}

本例中,我们为分组传入了自定义的 icon(),并让其默认折叠 collapsed()

排序导航分组

使用 navigationGroups(),你可以为导航分组定义新排序。如果你想要重新排序分组,而不是定义所有 NavigationGroup 对象,你可以以新的排序传入分组标签:

$panel
    ->navigationGroups([
        'Shop',
        'Blog',
        'Settings',
    ])

让导航分组不可折叠

默认情况下,导航分组是可折叠的。

Collapsible navigation groups

通过在 NavigationGroup 对象调用 collapsible(false),你可以禁用该行为:

use Filament\Navigation\NavigationGroup;

NavigationGroup::make()
    ->label('Settings')
    ->icon('heroicon-o-cog-6-tooth')
    ->collapsible(false);
Not collapsible navigation groups

或者,你可以在配置全局禁用可折叠,使之适用所有的分组:

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() 将只应用到当使用顶部导航时的顶部导航分组下拉菜单:

桌面端可折叠侧边栏

要让侧边栏在移动端和桌面端可折叠,你可以通过面板配置实现:

use Filament\Panel;

public function panel(Panel $panel): Panel
{
    return $panel
        // ...
        ->sidebarCollapsibleOnDesktop();
}
Collapsible sidebar on desktop

默认情况下,在桌面端折叠侧边栏时,导航图标仍会显示。你可以使用 sidebarFullyCollapsibleOnDesktop() 方法完全折叠侧边栏:

use Filament\Panel;

public function panel(Panel $panel): Panel
{
    return $panel
        // ...
        ->sidebarFullyCollapsibleOnDesktop();
}
Fully collapsible sidebar on desktop

桌面端可折叠侧边栏导航分组

NOTE

本章节仅适用于 sidebarCollapsibleOnDesktop(),不包括 sidebarFullyCollapsibleOnDesktop()。因为可全折叠 UI 会隐藏整个侧边栏而不只是修改其外观。

当在桌面端使用可折叠侧边栏时,你常常也会使用导航分组。默认情况下,每个导航分组的标签会在侧边栏折叠后隐藏,因为没有空间展示。即使导航分组是可折叠的,所有项目在折叠的侧边栏中仍然可见,因为没有分组标签可用于展开分组。

这个情况可以通过传入一个 icon() 到导航分组对象中来解决。该图标(而非导航项)将会始终显示在折叠后的侧边栏中。当点击该图标时,会在图标旁边打开下拉菜单,显示分组中的项目。

当传入图标到导航分组中时,即使这些项目有图标,展开的侧边栏 UI 也不会显示项目图标。这是为了使导航层次分明,以及设计最小化。不过,项目图标会显示在折叠后的侧边栏下拉菜单中,因为下拉菜单的打开已经使得层次事实上清晰明了了。

注册自定义导航项

要注册心的导航项,你可以使用面板配置

use Filament\Navigation\NavigationItem;
use Filament\Pages\Dashboard;
use Filament\Panel;
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-o-presentation-chart-line')
                ->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();
}
Top navigation

自定义侧边栏宽度

你可以在配置中将宽度传入到 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 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-o-home')
                    ->isActiveWhen(fn (): bool => original_request()->routeIs('filament.admin.pages.dashboard'))
                    ->url(fn (): string => Dashboard::getUrl()),
                ...UserResource::getNavigationItems(),
                ...Settings::getNavigationItems(),
            ]);
        });
}
Custom navigation items

注册自定义导航分组

如果你项注册分组,你可以调用 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(),
                    ]),
            ]);
        });
}

禁用导航

通过将 false 传递给 navigation() 方法,你可以完全禁用导航栏:

use Filament\Panel;

public function panel(Panel $panel): Panel
{
    return $panel
        // ...
        ->navigation(false);
}
Disabled navigation sidebar

禁用顶部栏

通过将 false 传递给 topbar() 方法,你可以完全禁用顶部栏:

use Filament\Panel;

public function panel(Panel $panel): Panel
{
    return $panel
        // ...
        ->topbar(false);
}

禁用面包屑

默认布局将显示面包屑导航,以指示当前页面在应用层次结构中的位置。

你可以在配置中禁用面包屑导航:

use Filament\Panel;

public function panel(Panel $panel): Panel
{
    return $panel
        // ...
        ->breadcrumbs(false);
}

重新加载侧边栏和顶部导航栏

当面板中的页面被加载时,侧边栏和顶部导航栏都不会重载,除非离开该页面或者点击菜单项去触发 Action。通过派发 refresh-sidebarrefresh-topbar 浏览器事件,你可以手动重载这些组件。

要使用 PHP 派发事件,你可以在任何 Livewire 组件(比如页面类,关联管理器类或者 Widget 类中)中调用 $this->dispatch() 方法:

$this->dispatch('refresh-sidebar');

如果代码不在某个 Livewire 组件中,比如在你自定义的 Action 类中, 你可以注入 $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'));
Edit on GitHub

Still need help? Join our Discord community or open a GitHub discussion