Bram 的回答帮助我找到了一个解决方案,这就是我所需要的以及我如何解决它(因为我是 ZF2 和命名空间的新手,所以我花费的时间比它应有的时间长得多,所以希望这对其他人有帮助)
问题
- 想要使用
Zend\Navigation
它来受益于它的isActive()
方法和内置的翻译、ACL 等支持。
- 需要将 CSS 类名称添加到
<li>
元素和 <a>
元素。(ZF2 的 Menu View Helper 目前支持“非此即彼”的方法)
- 需要将 CSS 类名称添加到嵌套
<ul>
元素。
- 需要向
<a>
元素添加其他属性,例如data-*="..."
- 需要这些更改来支持 Bootstrap 3 标记
解决方案说明
- 通过扩展创建客户视图助手
Zend\View\Helper\Navigation\Menu
- 稍微修改
renderNormalMenu()
和htmlify()
方法
- 利用添加自定义属性的能力为
Zend\Pages
某些元素添加 CSS 类和附加属性
解决方案
第1步
在 Application 模块下创建自定义 View Helpersrc\Application\View\Helper\NewMenu.php
新菜单.php
<?php
namespace Application\View\Helper;
// I'm extending this class, need to include it
use Zend\View\Helper\Navigation\Menu;
// Include namespaces we're using (from Zend\View\Helper\Navigation\Menu)
use RecursiveIteratorIterator;
use Zend\Navigation\AbstractContainer;
use Zend\Navigation\Page\AbstractPage;
class NewMenu extends Menu
{
// copied fromZend\View\Helper\Navigation\Menu
protected function renderNormalMenu(...){}
// copied from Zend\View\Helper\Navigation\Menu
public function htmlify(...){}
}
第2步
getViewHelperConfig()
在in 中注册了新的 View Helper\module\Application\Module.php
<?php
/**
* Zend Framework (http://framework.zend.com/) ...*/
namespace Application;
use Zend\Mvc\ModuleRouteListener;
use Zend\Mvc\MvcEvent;
class Module
{
// ** snip **
public function getViewHelperConfig() {
return array(
'invokables' => array(
// The 'key' is what is used to call the view helper
'NewMenu' => 'Application\View\Helper\NewMenu',
)
);
}
}
第 3 步
在我的layout.phtml
脚本中,我获取了我的 Navigation 容器并将其传递给 NewMenu 视图助手。我还设置了一些选项,例如添加父<ul>
类名称而不是转义标签,因此我可以将 Bootstrap 使用的标准“下拉插入符号”(即<b class="caret"></b>
)添加到带有下拉菜单的标签中。
$container = $this->navigation('navigation')->getContainer();
echo $this->NewMenu($container)->setUlClass('nav navbar-nav')->escapeLabels(false);
中场休息
此时,我们应该或多或少地复制了 Menu View Helper。它应该以与标准 View Helper 相同的方式生成导航。
第4步
在NewMenu.php
类中,我删除了$addClassToListItem
代码以避免它意外地将类放置在错误的元素上。
受保护的函数 renderNormalMenu(...)
// Add CSS class from page to <li>
//if ($addClassToListItem && $page->getClass()) {
// $liClasses[] = $page->getClass();
//}
公共函数 htmlify(...)
// Always apply page class to <a> tag. We'll use a diff. method for <li>
//if ($addClassToListItem === false) {
$attribs['class'] = $page->getClass();
//}
第 5 步
添加一个方法以将 CSS 类名称应用于<li>
标签,因为我们删除了该$addClassTolistItem
方法。我们只需使用 Page 类的能力来拥有自定义属性并执行此操作:
受保护的函数 renderNormalMenu
// Is page active?
if ($isActive) {
$liClasses[] = 'active';
}
if($wrapClass = $page->get('wrapClass')){
$liClasses[] = $wrapClass;
}
...
现在,在我们的 Navigation 配置文件中,我们可以简单地添加一个名为的属性wrapClass
,以将 CSS 类应用于包装元素 ( <li>
)。
配置\自动加载\global.php
...
'navigation' => array(
'default' => array(
...
array(
'label' => 'Products <b class="caret"></b>',
'route' => 'products',
'wrapClass' => 'dropdown', // class to <li>
'class' => 'dropdown-toggle', // class to <a> like usual
'pages' => array(
array(
'label' => 'Cars',
'route' => 'products/type',
...
),
...
),
),
...
第 6 步
<a>
添加在like上具有附加属性的功能data-*
。例如,对于 Bootstrap 3,您将需要data-toggle="dropdown"
。
公共函数 htmlify(...)
// get attribs for element
$attribs = array(
'id' => $page->getId(),
'title' => $title,
);
// add additional attributes
$attr = $page->get('attribs');
if(is_array($attr)){
$attribs = $attribs + $attr;
}
在您的配置文件中,您现在可以添加具有一系列附加属性的属性:
配置\自动加载\global.php
...
'navigation' => array(
'default' => array(
...
array(
'label' => 'Products <b class="caret"></b>',
'route' => 'products',
'wrapClass' => 'dropdown', // class to <li>
'class' => 'dropdown-toggle', // class to <a> like usual
'attribs' => array(
'data-toggle' => 'dropdown', // Key = Attr name, Value = Attr Value
),
'pages' => array(
array(
'label' => 'Cars',
'route' => 'products/type',
...
),
...
),
),
...
第 7 步
添加将类名放置在嵌套列表容器(即。<ul>
)上的功能。
受保护的函数 renderNormalMenu()
if ($depth > $prevDepth) {
// start new ul tag
if ($ulClass && $depth == 0) {
$ulClass = ' class="' . $ulClass . '"';
}
// Added ElseIf below
else if($ulClass = $page->get('pagesContainerClass')){
$ulClass = ' class="' . $ulClass . '"';
}
else {
$ulClass = '';
}
$html .= $myIndent . '<ul' . $ulClass . '>' . self::EOL;
原始代码基本上是说“如果这是第一个<ul>
并且有一个 UL 类,则添加它,否则什么也不做。所以,我添加了一个额外的检查来说明,如果一个名为的属性pagesContainerClass
可用,则将该类也应用于该类<ul>
。
这意味着我们需要在配置中的右侧页面上添加属性:
配置\自动加载\global.php
...
'navigation' => array(
'default' => array(
...
array(
'label' => 'Products <b class="caret"></b>',
'route' => 'products',
'wrapClass' => 'dropdown', // class to <li>
'class' => 'dropdown-toggle', // class to <a> like usual
'attribs' => array(
'data-toggle' => 'dropdown', // Key = Attr name, Value = Attr Value
),
'pages' => array(
array(
'label' => 'Cars',
'route' => 'products/type',
// Give child <ul> a class name
'pagesContainerClass' => 'dropdown-menu',
...
),
...
),
),
...
需要注意的重要一点是,UL 类需要放在孩子的第一个子页面上,因为条件语句被包装在以下条件中:
if ($depth > $prevDepth) {
// start new ul tag
...
}
在调用第一个孩子之后, $dept = $prevDepth 和嵌套<ul>
将已经被发送到字符串缓冲区。
此解决方案尚未经过严格测试,但其想法是简单地采用当前的 Menu View Helper,并重载两个必要的方法,并且只对其进行轻微修改。
我尝试过使用setPartial()
,但这只对<li>
生成有所帮助,它仍在使用 Menu View Helpers 的htmlify()
方法(所有这些都在 Bram 的上述讨论中提到)。
因此,通过将这些小 tweeks 放入 to 方法并使用 Page 类具有自定义属性的能力,我可以添加一些额外的逻辑来获取和嵌套类上<li>
的类名以及在元素上添加额外的属性,所以我可以从配置中配置我以吐出,基本上,Bootstrap 3 Navbar 标记。<a>
<ul>
<a>
Zend\Navigation
最终布局看起来像这样:
<nav class="navbar navbar-default navbar-static-top" role="navigation">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<div class="collapse navbar-collapse navbar-ex1-collapse">
<?php
// Use Zend\Navigation to create the menu
$container = $this->navigation('navigation')->getContainer();
echo $this->NewMenu($container)->setUlClass('nav navbar-nav')->escapeLabels(false);
?>
</div><!-- /.navbar-collapse -->
</nav>
我一直遇到的麻烦是更好地理解 PHP 命名空间,并且需要在我的自定义 View Helper 中包含适当的 Qualified 命名空间,即使我正在扩展它。
另一个问题是 Navigation View Helper 可以从自身调用 Menu View Helper,如下所示:
$this->navigation('navigation')->menu();
这不起作用:
$this->navigation('navigation')->NewMenu();
由于命名空间问题,我正在考虑NewMenu
未在 Navigation View Helper 类中注册,因此我不会为此扩展它。
因此,希望这个(长)答案能帮助其他正在努力解决这种需求的人。
干杯!