tobento/service-menu

简单流畅的菜单构建器。

1.1.3 2024-09-15 07:06 UTC

This package is auto-updated.

Last update: 2024-09-15 07:08:55 UTC


README

使用菜单服务,您可以轻松构建菜单。

目录

入门

运行此命令添加菜单服务项目的最新版本。

composer require tobento/service-menu

要求

  • PHP 8.0或更高版本

亮点

  • 框架无关,适用于任何项目
  • 解耦设计

简单示例

以下是一个使用菜单服务的简单示例。

use Tobento\Service\Menu\Menu;
use Tobento\Service\Menu\Item;
use Tobento\Service\Menu\Link;

$menu = (new Menu('footer'))
    ->add(new Item('about us'))
    ->add(new Link('/contact', 'contact'))
    ->add(new Item('team', null, 'about us'));

$menu = new Menu('footer');
$menu->item('about us');
$menu->link('/contact', 'contact');
$menu->item('team')->parent('about us');

渲染菜单

<?= $menu->render() ?>

// or just
<?= $menu ?>

上面的两个菜单都将产生以下输出。

<ul>
    <li>about us
        <ul>
            <li>team</li>
        </ul>
    </li>
    <li><a href="/contact">contact</a></li>
</ul>

文档

菜单

创建菜单项

使用add()方法创建项。

use Tobento\Service\Menu\Menu;
use Tobento\Service\Menu\Item;
use Tobento\Service\Menu\Link;
use Tobento\Service\Menu\Html;

$menu = (new Menu('footer'))
    ->add(new Item('about us'))
    ->add(new Link('/contact', 'contact'))
    ->add(new Html('html')); // must be escaped!

使用内置方法创建项。

use Tobento\Service\Menu\Menu;

$menu = new Menu('footer');
$item = $menu->item('about us');
$linkItem = $menu->link('/contact', 'contact');
$htmlItem = $menu->html('html'); // must be escaped!

使用many()方法创建项。

use Tobento\Service\Menu\Menu;

$items = [
    [
        'name' => 'about',
    ],
    [
        'name' => 'contact',
    ],
    [
        'name' => 'team',
        'parent' => 'about',
    ],    
];

$menu = (new Menu('footer'))->many($items, function($menu, $item) {
    
    $menu->link('/'.$item['name'], $item['name'])
         ->parent($item['parent'] ?? null);
});

创建子项

通过定义父项的id创建子项。

use Tobento\Service\Menu\Menu;
use Tobento\Service\Menu\Item;
use Tobento\Service\Menu\Link;

$menu = (new Menu('footer'))
    ->add(new Item('about us'))
    ->add(new Item('team', parent: 'about us'));

$menu = new Menu('footer');
$menu->item('about us');
$menu->item('team')->parent('about us');

// or by defining an id
$menu = (new Menu('footer'))
    ->add(new Item('about us', id: 'about'))
    ->add(new Item('team', parent: 'about'));
    
$menu = new Menu('footer');
$menu->item('about us')->id('about');
$menu->item('team')->parent('about');

附加菜单项

链接到第一个子项

LinkToFirstChild菜单项,如果存在,则链接到第一个子菜单链接,否则根本不会渲染。

use Tobento\Service\Menu\LinkToFirstChild;
use Tobento\Service\Menu\Menu;

$menu = new Menu('main');
$menu->add((new LinkToFirstChild($menu, 'Settings'))->id('settings'));
$menu->link('/locales', 'locales')->parent('settings');

图标

use Tobento\Service\Menu\Menu;

$menu = new Menu('header');
$menu->link('/login', 'Login')->icon(name: 'login');

// you may define a position for all icons:
$menu->iconPosition('left');

创建图标

默认情况下,图标根本不会创建。

以下是一个创建图标的简单示例

use Tobento\Service\Menu\Str;

$menu->each(static function($item, $menu) {
    if (!$item->getIcon()) {
        return $item;
    }

    $html = '<i class="fa-light fa-'.Str::esc($item->getIcon()).'"></i>';
    
    if ($menu->getIconPosition() === 'right') {
        $item->tag()->append(html: $html);
    } else {
        $item->tag()->prepend(html: $html);
    }
    
    return $item;
});

使用图标服务创建图标

您可以使用菜单图标工厂通过图标服务创建图标。

use Tobento\Service\Menu\MenuIconsFactory;
use Tobento\Service\Icon\IconsInterface;

$menuFactory = new MenuIconsFactory(
    icons: $icons, // IconsInterface
);

$menu = $menuFactory->createMenu(name: 'header');

仅渲染图标

如果只想渲染图标,请使用onlyIcons方法

$menu->onlyIcons();

徽章

徽章可以用于向菜单项添加更多信息

use Tobento\Service\Menu\Menu;

$menu = new Menu('header');
$menu->link('/invoices', 'Invoices')->badge(text: '10', attributes: ['title' => '10 new invoices']);

输出

<ul>
    <li><a href="/invoices">Invoices<span title="10 new invoices" class="badge">10</span></a></li>
</ul>

徽章如果

您可以使用badgeIf方法,该方法仅在给定的badge参数值验证为true时渲染徽章。

use Tobento\Service\Menu\Menu;

$invoiceCount = 10;

$menu = new Menu('header');
$menu->link('/invoices', 'Invoices')->badgeIf(
    badge: $invoiceCount > 0, // bool
    text: (string)$invoiceCount,
    attributes: [],
);

排序项

use Tobento\Service\Menu\Menu;

$menu = new Menu('footer');
$menu->item('team');
$menu->item('about');

$menu->sort(fn ($a, $b) => $a->text() <=> $b->text());

迭代项

使用过滤方法

use Tobento\Service\Menu\Menu;

$menu = new Menu('footer');
$menu->item('team');
$menu->item('about');

$menu->filter(fn($i) => $i->text() === 'team');

使用具有访问数据树和标签的each方法

use Tobento\Service\Menu\Menu;

$menu = new Menu('footer');
$menu->item('team');
$menu->item('about');

$menu->each(function($item, $menu) {
    
    $parentTag = $item->parentTag();
    $itemTag = $item->itemTag();
    $treeLevel = $item->getTreeLevel();
    $treeId = $item->getTreeId();
    $treeParent = $item->getTreeParent();
    $treeParentItem = $item->getTreeParentItem();
    $treeChildren = $item->getTreeChildren();
    
    return $item;
});

在特定项上

use Tobento\Service\Menu\Menu;

$menu = new Menu('footer');
$menu->item('team');
$menu->item('about');

$menu->on('team', function($item, $menu) {
        
    $item->itemTag()->class('foo');
    $item->parentTag()->class('bar');
    
    return $item;
});
<ul class="bar">
    <li class="foo">team</li>
    <li>about</li>
</ul>

在父项上

use Tobento\Service\Menu\Menu;

$menu = new Menu('footer');
$menu->item('team')->parent('about');
$menu->item('about');
$menu->item('contact');

$menu->onParents('team', function($item, $menu) {
    
    $item->itemTag()->class('foo');
    
    return $item;
});
<ul>
    <li class="foo">about
        <ul>
            <li class="foo">team</li>
        </ul>
    </li>
    <li>contact</li>
</ul>

活动项

use Tobento\Service\Menu\Menu;

$menu = new Menu('footer');
$menu->item('team')->parent('about');
$menu->item('about');
$menu->item('contact');
$menu->item('form')->parent('contact');

// set the form item and all its parent items active.
$menu->active('form');
<ul>
    <li>about
        <ul>
            <li>team</li>
        </ul>
    </li>
    <li>contact
        <ul>
            <li>form</li>
        </ul>
    </li>
</ul>

仅渲染活动树项

use Tobento\Service\Menu\Menu;

$menu = new Menu('footer');
$menu->item('team')->parent('about');
$menu->item('about');
$menu->item('contact');
$menu->item('form')->parent('contact');

// set the form item active.
$menu->active('form');

// do not render any inactive tree items.
$menu->subitems(false);
<ul>
    <li>about</li>
    <li>contact
        <ul>
            <li>form</li>
        </ul>
    </li>
</ul>

在项本身上设置项的活动状态

use Tobento\Service\Menu\Menu;

$menu = new Menu('footer');
$menu->item('team')->parent('about');
$menu->item('about');
$menu->item('contact')->active();
$menu->item('form')->parent('contact')->active();

// do no render any inactive tree items.
$menu->subitems(false);
<ul>
    <li>about</li>
    <li>contact
        <ul>
            <li>form</li>
        </ul>
    </li>
</ul>

获取项

注意:除了项标签外,项树数据和标签目前不可用

获取单个项

use Tobento\Service\Menu\Menu;

$menu = new Menu('footer');
$menu->item('team');

$menu->get('team')->itemTag()->class('active');

获取所有项

use Tobento\Service\Menu\Menu;

$menu = new Menu('footer');
$menu->item('team');

$items = $menu->all();

标签

使用标签可以管理渲染的菜单标签。

菜单标签

use Tobento\Service\Menu\Menu;
use Tobento\Service\Menu\Tag;
use Tobento\Service\Menu\NullTag;

$menu = new Menu('footer');

// add class foo to every ul tag.
$menu->tag('ul')->class('foo');

// add class foo only to every ul tag with depth level 1.
$menu->tag('ul')->level(1)->class('foo');

// add class foo to every li tag.
$menu->tag('li')->class('foo');

// add class foo and bar only to every li tag with depth level 2.
$menu->tag('li')->level(2)->class('foo')->class('bar');

// add any attribute with the attr() method.
$menu->tag('li')->attr('data-foo', '1');

// change every ul tag to ol tag.
$menu->tag('ul')->handle(fn() => new Tag('ol'));

// assign current level so that other
// level tag attributes get assigned.
$menu->tag('ul')->handle(fn(Tag $t) => (new Tag('ol'))->level($t->getLevel()));

// change every ul tag to div tag.
$menu->tag('ul')->handle(fn() => new Tag('div'));

// change every li tag to a null tag and prepend and append a character.
$menu->tag('li')->handle(fn() => (new NullTag())->prepend('[')->append(']'));

// get tag attributes.
$attributes = $menu->tag('li')->attributes();

// check if there are any attributes.
$empty = $attributes->empty();

// check if there is a specific attribute.
$hasClassAttr = $attributes->has('class');

// get any attribute.
$classAttr = $attributes->get('class');

// get any attribute.
$classAttr = $attributes->get('class');

// get all attributes.
$allAttributes = $attributes->all();

// set an attribute.
$attributes->set('data-foo', '1');

// add an attribute (merges).
$attributes->add('data-foo', '1');

// merge an attribute.
$attributes->merge('data-foo', '1');

项标签

use Tobento\Service\Menu\Menu;

$menu = new Menu('footer');
$item = $menu->link('/contact', 'contact');

// The item tag.
$item->itemTag()->class('bar');

// The tag: link items have for instance its own tag. The a tag.
$item->tag()->class('foo');

// The parent tag is not yet available.
var_dump($item->parentTag()); // NULL
// Use each(), on(), onParents() methods if you need to manage the parent tag.

转义

在渲染菜单时,已为您执行HTML转义。除Tag类外,您需要自行执行

use Tobento\Service\Menu\Tag;

$tag = new Tag('a', htmlspecialchars('html', ENT_QUOTES, 'UTF-8'));

$tag->content(htmlspecialchars('html', ENT_QUOTES, 'UTF-8'));
$tag->append(htmlspecialchars('html', ENT_QUOTES, 'UTF-8'));
$tag->prepend(htmlspecialchars('html', ENT_QUOTES, 'UTF-8'));

菜单

use Tobento\Service\Menu\Menus;
use Tobento\Service\Menu\Menu;

// Create menus.
$menus = new Menus();

// Create menus with a custom menu factory.
$menus = new Menus(new CustomMenuFactory());

// Add a menu.
$menus->add(new Menu('main'));

// Get the main menu. If it does not exist, it returns null.
$menus->get('main');

// Get the main menu. If it does not exist, it creates a new one.
$menus->menu('main')
      ->item('about')
      ->order(1000);

示例

仅向活动项添加活动类

use Tobento\Service\Menu\Menu;

$menu = new Menu('footer');
$menu->item('team')->parent('about');
$menu->item('about');
$menu->item('contact');
$menu->item('form')->parent('contact');

$menu->on('form', function($item, $menu) {
    $item->itemTag()->class('active');
    $item->parentTag()->class('active');
    return $item;
});
<ul>
    <li>about
        <ul>
            <li>team</li>
        </ul>
    </li>
    <li>contact
        <ul class="active">
            <li class="active">form</li>
        </ul>
    </li>
</ul>

向活动项添加活动类

use Tobento\Service\Menu\Menu;

$menu = new Menu('footer');
$menu->item('team')->parent('about');
$menu->item('about');
$menu->item('contact');
$menu->item('form')->parent('contact');

$menu->onParents('form', function($item, $menu) {
        
    $item->itemTag()->class('active');
    
    if ($item->getTreeLevel() > 0) {
        $item->parentTag()->class('active');
    }
    
    $item->tag()->class('active');
    
    return $item;
});

// do only render active tree.
$menu->active('form')
     ->subitems(false);
<ul>
    <li>about</li>
    <li class="active">
        <a class="active" href="/contact">contact</a>
        <ul class="active">
            <li class="active">form</li>
        </ul>
    </li>
</ul>

致谢