Yii2:创建自定义菜单

Yii2 : Create custom menu

我构建了一个 bootstrap 菜单,现在我想用 Yii2 Nav 小部件重现它。所以,这是初始状态:

<nav class="navbar navbar-inverse" role="navigation">
    <div class="container">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="true">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="/">BrandLogo</a>
        </div>
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1" aria-expanded="true">
            <ul class="nav navbar-nav">
                <li>
                    <a href="#1" class="current">simple menu</a>
                </li>
                <li class="dropdown">
                    <a href="#4">dropdown menu <b class="caret"></b></a>
                    <ul class="dropdown-menu">
                        <li>
                            <a href="#2">Submenu#1</a>
                        </li>
                        <li>
                            <a href="#3">Submenu#2</a>
                        </li>
                    </ul>
                </li>
            </ul>
            <form class="navbar-form navbar-left" action="/action_page.php">
                <div class="form-group has-feedback search">
                    <input type="text" class="form-control" placeholder="Search" />
                    <i class="glyphicon glyphicon-search form-control-feedback"></i>
                </div>
            </form>
        </div>
    </div>
</nav>

它是这样的:

现在我想用 Nav 小部件做同样的菜单。这是代码:

NavBar::begin([
    'brandLabel' => 'BrandLogo',
    'brandUrl' => Yii::$app->homeUrl,
    'options' => [
        'class' => 'navbar-inverse',
    ],
]);

$menuItems = [
    [
        'label' => 'simple menu',
        'url' => ['#1']
    ],
    [
        'label' => 'dropdown menu',
        'url' => ['#4'],
        'items' => [
            [
                'label' => 'Submenu#1',
                'url' => ['#1'],
            ],
            [
                'label' => 'Submenu#2',
                'url' => ['#2'],
            ],
        ]
    ],
    [
        'label' => '
            <form class="navbar-form navbar-left" action="/action_page.php">
                <div class="form-group has-feedback search">
                    <input type="text" class="form-control" placeholder="Search" />
                    <i class="glyphicon glyphicon-search form-control-feedback"></i>
                </div>
            </form>',
        'encode' => false,
        'url' => false,
    ],
];


if (count($menuItems)) {
    echo Nav::widget([
        'options' => ['class' => 'navbar-nav'],
        'items' => $menuItems,
    ]);
}

NavBar::end();

问题是结果不相等。我发现了一些问题:

  1. 小部件生成下拉列表 link 作为 <a class="dropdown-toggle" href="/main/#4" data-toggle="dropdown">dropdown menu <span class="caret"></span></a> 我怎样才能去掉 data-toggle="dropdown"class="dropdown-toggle"
  2. 搜索表单包含在 <a></a> 标签中。这就是导航栏损坏的原因: 我怎样才能摆脱不必要的标签?

那是因为你没有遵循实际的 HTML 结构,因此你需要在 ul 之后添加表格,而不是在 li 内部,而是那个表格应该是 NavBar 的一部分,如果您查看定义

Any content enclosed between the \yii\bootstrap\begin() and \yii\bootstrap\end() calls of NavBar is treated as the content of the navbar. You may use widgets such as yii\bootstrap\Nav or \yii\widgets\Menu to build up such content.

因此,在调用 Nav::widget() 之后和调用 NavBar::end() 之前,只需将表单移到 $items 之外即可。

并且您可以使用 linkOptions 自定义或删除 class 或与 link

相关的任何其他属性
<?php
NavBar::begin([
    'brandLabel' => 'BrandLogo',
    'brandUrl' => Yii::$app->homeUrl,
    'options' => [
        'class' => 'navbar-inverse',
    ],
]);

$menuItems = [
    [
        'label' => 'simple menu',
        'url' => ['#1']
    ],
    [
        'label' => 'dropdown menu',
        'url' => ['#4'],
        'linkOptions' => [
            'class' => 'my-class',
            'data' => [
                'toggle' => ''
            ]
        ],
        'items' => [
            [
                'label' => 'Submenu#1',
                'url' => ['#1'],
            ],
            [
                'label' => 'Submenu#2',
                'url' => ['#2'],
            ],
        ]
    ],
];


if( count($menuItems) ){
    echo Nav::widget([
        'options' => ['class' => 'navbar-nav'],
        'items' => $menuItems,
    ]);
}
?>
<form class="navbar-form navbar-left" action="/action_page.php">
    <div class="form-group has-feedback search">
        <input type="text" class="form-control" placeholder="Search" />
        <i class="glyphicon glyphicon-search form-control-feedback"></i>
    </div>
</form>
<?php
NavBar::end();

编辑

如果您希望完全删除 class 名称 dropdown-toggle,那么您可能必须通过扩展小部件来覆盖 yii\bootstrap\Nav::renderItems(),因为它默认添加为 bootstrap class 所以你只需将 renderItems() 复制到你的扩展 class 并注释掉 Html::addCssClass ( $linkOptions , [ 'widget' => 'dropdown-toggle' ] ); 行,它在那里添加了 class 然后更改namespace 您在其中调用 Navyii\bootstrap\Nav::widget()common\components\Nav::widget()

在您的 common\components\ 中添加以下 class 或者如果您打算将其复制到其他地方,请更新代码中的命名空间

<?php

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

namespace common\components;

use yii\bootstrap\Nav as BaseNav;
use yii\bootstrap\Html;
use yii\helpers\ArrayHelper;
use yii\base\InvalidConfigException;

class Nav extends BaseNav {

    /**
     * Renders a widget's item.
     * @param string|array $item the item to render.
     * @return string the rendering result.
     * @throws InvalidConfigException
     */
    public function renderItem($item) {
        if( is_string($item) ){
            return $item;
        }
        if( !isset($item['label']) ){
            throw new InvalidConfigException("The 'label' option is required.");
        }
        $encodeLabel = isset($item['encode']) ? $item['encode'] : $this->encodeLabels;
        $label = $encodeLabel ? Html::encode($item['label']) : $item['label'];
        $options = ArrayHelper::getValue($item, 'options', []);
        $items = ArrayHelper::getValue($item, 'items');
        $url = ArrayHelper::getValue($item, 'url', '#');
        $linkOptions = ArrayHelper::getValue($item, 'linkOptions', []);

        if( isset($item['active']) ){
            $active = ArrayHelper::remove($item, 'active', false);
        } else{
            $active = $this->isItemActive($item);
        }

        if( empty($items) ){
            $items = '';
        } else{
            $linkOptions['data-toggle'] = 'dropdown';
            Html::addCssClass($options, ['widget' => 'dropdown']);
//            Html::addCssClass ( $linkOptions , [ 'widget' => 'dropdown-toggle' ] );
            if( $this->dropDownCaret !== '' ){
                $label .= ' ' . $this->dropDownCaret;
            }
            if( is_array($items) ){
                $items = $this->isChildActive($items, $active);
                $items = $this->renderDropdown($items, $item);
            }
        }

        if( $active ){
            Html::addCssClass($options, 'active');
        }

        return Html::tag('li', Html::a($label, $url, $linkOptions) . $items, $options);
    }

}