自动设置活动项目

Set active item automatically

我的应用程序中有一个菜单:

<?php
NavBar::begin([
    'brandLabel' => Html::img('@web/images/logo-top.png', ['id' => 'logo']),
    'brandUrl' => Yii::$app->homeUrl,
    'options' => [
        'class' => 'navbar-inverse navbar-static-top',
    ],
]);

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

<?php NavBar::end(); ?>

$menuItems在一个Controller中生成:

private function constructMenu($categories) {
    $menu = [];

    if (is_array($categories) && (count($categories) > 0)) {
        foreach($categories as $key => $category) {
            $menu[$key] = [
                'label' => $category['name'],
                'url' => Url::to([
                    'category/view',
                    'slug' => $category['slug']
                ]),
            ];
            if (is_array($category['children']) && (count($category['children']) > 0)) {
                $menu[$key]['items'] = $this->constructMenu($category['children']);
            }
        }
    }

    return $menu;
}

我还有 urlManager 配置:

'urlManager' => [
    'enablePrettyUrl' => true,
    'showScriptName' => false,
    'rules' => [
        'category/<slug:[\w_-]+>' => 'category/view',
        'item/<slug:[\w_-]+>' => 'item/view',
        'cart/remove/<item_id:\d+>' => 'cart/remove',
        'cart/add/<item_id:\d+>' => 'cart/add',
    ],
],

所以,唯一的问题是菜单项总是 active = false。我应该如何修改 constructMenu 方法来为 active 键设置正确的值?或者我应该在模板中完成?

以下是来自 PhpStrom 调试面板的 $menuItems 的内容,就在它被传递给 Nav::widget 之前:

这是我现在所在的位置:

NavBar::begin([
    'brandLabel' => Html::img('@web/images/logo-top.png',
        ['id' => 'logo', 'style' => 'height: 40px; filter: invert(100%);']),
    'brandUrl' => Yii::$app->homeUrl,
    'options' => [
        'class' => 'navbar-inverse navbar-static-top',
    ],
]);

$controllerAndSlug = $this->context->id . '/' . $this->context->actionParams['slug'];
$menuItems = array_map(
    function($item) use ($controllerAndSlug) {
        $item['active'] = strpos($item['url'], $controllerAndSlug) !== false;
        return $item;
    },
    $menuItems
);

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

它工作正常,但仅在顶级菜单项上设置 active 标志。现在我想知道如何将参数传递给 callback-function.

试试这个:

private function constructMenu($categories) {
    $menu = [];

    if (is_array($categories) && (count($categories) > 0)) {
        foreach($categories as $key => $category) {
            $menu[$key] = [
                'label' => $category['name'],
                'url' => Url::to([
                    'category/view',
                    'slug' => $category['slug']
                ]),
                'active' => Yii::$app->controller->id == 'category' 
                     && Yii::$app->controller->action->id == 'view'
                     && Yii::$app->request->get('slug') == $category['slug']
            ];
            if (is_array($category['children']) && (count($category['children']) > 0)) {
                $menu[$key]['items'] = $this->constructMenu($category['children']);
            }
        }
    }

    return $menu;
}

尽管如果您提供完整的 URL 和 /controller/action 格式,它应该可以工作,如果仍然不能,那么您可以使用 itemactive 选项通过检查当前控制器、动作和 slug

protected function constructMenu($categories) {

    $menu = [];
    $controller = Yii::$app->controller->id;
    $action = Yii::$app->controller->action->id;
    $slug = Yii::$app->request->get('slug');

    if( is_array($categories) && (count($categories) > 0) ){
        foreach( $categories as $key => $category ){
            $isActive = ($controller == 'category' && $action == 'view' && $slug == $category['slug']);
            $menu[$key] = [
                'label' => $category['name'],
                'url' => Url::to([
                    'category/view',
                    'slug' => $category['slug']
                ]),
                'active' => $isActive
            ];
            if( is_array($category['children']) && (count($category['children']) > 0) ){
                $menu[$key]['items'] = $this->constructMenu($category['children']);
            }
        }
    }

    return $menu;
}