tobento / service-menu
简单流畅的菜单构建器。
1.1.3
2024-09-15 07:06 UTC
Requires
- php: >=8.0
- tobento/service-tag: ^1.0
- tobento/service-treeable: ^1.0
Requires (Dev)
- phpunit/phpunit: ^9.5
- tobento/service-icon: ^1.0
- vimeo/psalm: ^4.0
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>