KnpMenuBundle 不适用于 Bootstrap 4 导航栏
KnpMenuBundle not working with Bootstrap 4 navbar
我目前正在使用 Symfony 包制作菜单:KnpMenuBundle。我正在使用 Bootstrap 4 作为样式表。
Bootstrap 4 要求导航栏中的每个列表项都具有 class 'nav-item':
<li class="nav-item active"> <-- this
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
我似乎无法弄清楚如何使用 KnpMenuBundle 将 class 'nav-item' 添加到列表项。目前我在加载页面时看到这个:
navbar result
这是我在 src/AppBundle/Menu 中的生成器 class:
namespace AppBundle\Menu;
use Knp\Menu\MenuFactory;
class Builder
{
public function mainMenu(MenuFactory $factory, array $optioins)
{
$menu = $factory->createItem('root');
$menu->setChildrenAttribute('class', 'navbar-nav mr-auto');
$menu->addChild('Home', ['route' => 'homepage']);
$menu->setChildrenAttributes(['class' => 'nav-item']);
return $menu;
}
}
我在 base.html.twig 中生成菜单的代码:
{{ knp_menu_render('AppBundle:Builder:mainMenu', {'currentClass': 'active'}) }}
我该怎么做才能让它发挥作用?
您可以在添加时为每个子项目添加一个 class:
$menu->addChild('Home', ['route' => 'homepage'])
->setAttributes(array(
'class' => 'nav-item'
));
我这样做是为了让顶级正确。不过还没有制定下拉菜单。
$menu->setChildrenAttribute('class', 'navbar-nav');
// menu items
foreach ($menu as $child) {
$child->setLinkAttribute('class', 'nav-link')
->setAttribute('class', 'nav-item');
}
您应该创建新的模板文件,例如 "extended_knp_menu.html.twig"(另外文件名 不应 命名为 knp_menu.html.twig), 内容 (src):
{% extends 'knp_menu.html.twig' %}
{% macro setCssClassAttribute(item, type, add) %}
{% set getter = 'get' ~ type %}
{% set setter = 'set' ~ type %}
{% set value = attribute(item, getter, ['class']) %}
{% if value is iterable %}
{% set value = value|join(' ') %}
{% endif %}
{% do attribute(item, setter, ['class', value ~ ' ' ~ add]) %}
{% endmacro %}
{% block item %}
{% import "knp_menu.html.twig" as macros %}
{#
As multiple level is not currently supported by bootstrap 4
This requires you to install
https://github.com/bootstrapthemesco/bootstrap-4-multi-dropdown-navbar
And set the the use_multilevel = true
#}
{% set use_multilevel = false %}
{% if item.displayed %}
{%- set attributes = item.attributes %}
{%- set is_dropdown = attributes.dropdown|default(false) %}
{%- set divider_prepend = attributes.divider_prepend|default(false) %}
{%- set divider_append = attributes.divider_append|default(false) %}
{# unset bootstrap specific attributes #}
{%- set attributes = attributes|merge({'dropdown': null, 'divider_prepend': null, 'divider_append': null }) %}
{%- if divider_prepend %}
{{ block('dividerElement') }}
{%- endif %}
{# building the class of the item #}
{%- set classes = item.attribute('class') is not empty ? [item.attribute('class'), 'nav-item'] : ['nav-item'] %}
{%- if matcher.isCurrent(item) %}
{%- set classes = classes|merge([options.currentClass]) %}
{%- elseif matcher.isAncestor(item, options.depth) %}
{%- set classes = classes|merge([options.ancestorClass]) %}
{%- endif %}
{%- if item.actsLikeFirst %}
{%- set classes = classes|merge([options.firstClass]) %}
{%- endif %}
{%- if item.actsLikeLast %}
{%- set classes = classes|merge([options.lastClass]) %}
{%- endif %}
{# building the class of the children #}
{%- set childrenClasses = item.childrenAttribute('class') is not empty ? [item.childrenAttribute('class')] : [] %}
{%- set childrenClasses = childrenClasses|merge(['menu_level_' ~ item.level]) %}
{# adding classes for dropdown #}
{%- if is_dropdown %}
{%- set classes = classes|merge(['dropdown']) %}
{%- set childrenClasses = childrenClasses|merge(['dropdown-menu']) %}
{%- endif %}
{# putting classes together #}
{%- if classes is not empty %}
{%- set attributes = attributes|merge({'class': classes|join(' ')}) %}
{%- endif %}
{%- set listAttributes = item.childrenAttributes|merge({'class': childrenClasses|join(' ') }) %}
<li{{ macros.attributes(attributes) }}>
{# displaying the item #}
{%- if is_dropdown %}
{{ block('dropdownElement') }}
{%- elseif item.uri is not empty and (not item.current or options.currentAsLink) %}
{{ block('linkElement') }}
{%- else %}
{{ block('spanElement') }}
{%- endif %}
{%- if divider_append %}
{{ block('dividerElement') }}
{%- endif %}
{% if item.hasChildren and options.depth is not same as(0) and item.displayChildren %}
{{ block('dropdownlinks') }}
{% endif %}
</li>
{% endif %}
{% endblock %}
{% block dropdownlinks %}
{% if use_multilevel %}
<ul class="dropdown-menu">
{% else %}
<div class="dropdown-menu">
{% endif %}
{% for item in item.children %}
{{ block('renderDropdownlink') }}
{% if use_multilevel and item.hasChildren and options.depth is not same as(0) and item.displayChildren %}
{{ block('dropdownlinks') }}
{% endif %}
{% endfor %}
{% if not use_multilevel %}
</div>
{% else %}
</ul>
{% endif %}
{% endblock %}
{% block renderDropdownlink %}
{% import _self as ownmacro %}
{%- set divider_prepend = item.attributes.divider_prepend|default(false) %}
{%- set divider_append = item.attributes.divider_append|default(false) %}
{%- set attributes = item.attributes|merge({'dropdown': null, 'divider_prepend': null, 'divider_append': null }) %}
{% if use_multilevel %}
<li>
{% endif %}
{%- if divider_prepend %}
{{ block('dividerElementDropdown') }}
{%- endif %}
{%- if item.uri is not empty and (not item.current or options.currentAsLink) %}
{{ ownmacro.setCssClassAttribute(item, 'LinkAttribute', 'dropdown-item') }}
{{ block('linkElement') }}
{%- else %}
{{ block('spanElementDropdown') }}
{%- endif %}
{%- if divider_append %}
{{ block('dividerElementDropdown') }}
{%- endif %}
{% if use_multilevel %}
</li>
{% endif %}
{% endblock %}
{% block spanElementDropdown %}
{% import "knp_menu.html.twig" as macros %}
{% import _self as ownmacro %}
{{ ownmacro.setCssClassAttribute(item, 'LabelAttribute', 'dropdown-header') }}
<div {{ macros.attributes(item.labelAttributes) }}>
{% if item.attribute('icon') is not empty %}
<i class="{{ item.attribute('icon') }}"></i>
{% endif %}
{{ block('label') }}
</div>
{% endblock %}
{% block dividerElementDropdown %}
<div class="dropdown-divider"></div>
{% endblock %}
{% block dividerElement %}
{% if item.level == 1 %}
<li class="divider-vertical"></li>
{% else %}
<li class="divider"></li>
{% endif %}
{% endblock %}
{% block linkElement %}
{% import "knp_menu.html.twig" as macros %}
{% import _self as ownmacro %}
{{ ownmacro.setCssClassAttribute(item, 'LinkAttribute', 'nav-link') }}
<a href="{{ item.uri }}"{{ macros.attributes(item.linkAttributes) }}>
{% if item.attribute('icon') is not empty %}
<i class="{{ item.attribute('icon') }}"></i>
{% endif %}
{{ block('label') }}
</a>
{% endblock %}
{% block spanElement %}
{% import "knp_menu.html.twig" as macros %}
{% import _self as ownmacro %}
{{ ownmacro.setCssClassAttribute(item, 'LabelAttribute', 'navbar-text') }}
<span {{ macros.attributes(item.labelAttributes) }}>
{% if item.attribute('icon') is not empty %}
<i class="{{ item.attribute('icon') }}"></i>
{% endif %}
{{ block('label') }}
</span>
{% endblock %}
{% block dropdownElement %}
{% import "knp_menu.html.twig" as macros %}
{%- set classes = item.linkAttribute('class') is not empty ? [item.linkAttribute('class')] : [] %}
{%- set classes = classes|merge(['dropdown-toggle', 'nav-link']) %}
{%- set attributes = item.linkAttributes %}
{%- set attributes = attributes|merge({'class': classes|join(' ')}) %}
{%- set attributes = attributes|merge({'data-toggle': 'dropdown'}) %}
<a href="#"{{ macros.attributes(attributes) }}>
{% if item.attribute('icon') is not empty %}
<i class="{{ item.attribute('icon') }}"></i>
{% endif %}
{{ block('label') }}
<b class="caret"></b>
</a>
{% endblock %}
{% block label %}{{ item.label|trans }}{% endblock %}
仅包含菜单渲染模板后:
{{ knp_menu_render('AppBundle:Builder:mainMenu', {
'currentClass': 'active',
'template': 'extended_knp_menu.html.twig'
}) }}
希望对你有所帮助。
我目前正在使用 Symfony 包制作菜单:KnpMenuBundle。我正在使用 Bootstrap 4 作为样式表。
Bootstrap 4 要求导航栏中的每个列表项都具有 class 'nav-item':
<li class="nav-item active"> <-- this
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
我似乎无法弄清楚如何使用 KnpMenuBundle 将 class 'nav-item' 添加到列表项。目前我在加载页面时看到这个: navbar result
这是我在 src/AppBundle/Menu 中的生成器 class:
namespace AppBundle\Menu;
use Knp\Menu\MenuFactory;
class Builder
{
public function mainMenu(MenuFactory $factory, array $optioins)
{
$menu = $factory->createItem('root');
$menu->setChildrenAttribute('class', 'navbar-nav mr-auto');
$menu->addChild('Home', ['route' => 'homepage']);
$menu->setChildrenAttributes(['class' => 'nav-item']);
return $menu;
}
}
我在 base.html.twig 中生成菜单的代码:
{{ knp_menu_render('AppBundle:Builder:mainMenu', {'currentClass': 'active'}) }}
我该怎么做才能让它发挥作用?
您可以在添加时为每个子项目添加一个 class:
$menu->addChild('Home', ['route' => 'homepage'])
->setAttributes(array(
'class' => 'nav-item'
));
我这样做是为了让顶级正确。不过还没有制定下拉菜单。
$menu->setChildrenAttribute('class', 'navbar-nav');
// menu items
foreach ($menu as $child) {
$child->setLinkAttribute('class', 'nav-link')
->setAttribute('class', 'nav-item');
}
您应该创建新的模板文件,例如 "extended_knp_menu.html.twig"(另外文件名 不应 命名为 knp_menu.html.twig), 内容 (src):
{% extends 'knp_menu.html.twig' %}
{% macro setCssClassAttribute(item, type, add) %}
{% set getter = 'get' ~ type %}
{% set setter = 'set' ~ type %}
{% set value = attribute(item, getter, ['class']) %}
{% if value is iterable %}
{% set value = value|join(' ') %}
{% endif %}
{% do attribute(item, setter, ['class', value ~ ' ' ~ add]) %}
{% endmacro %}
{% block item %}
{% import "knp_menu.html.twig" as macros %}
{#
As multiple level is not currently supported by bootstrap 4
This requires you to install
https://github.com/bootstrapthemesco/bootstrap-4-multi-dropdown-navbar
And set the the use_multilevel = true
#}
{% set use_multilevel = false %}
{% if item.displayed %}
{%- set attributes = item.attributes %}
{%- set is_dropdown = attributes.dropdown|default(false) %}
{%- set divider_prepend = attributes.divider_prepend|default(false) %}
{%- set divider_append = attributes.divider_append|default(false) %}
{# unset bootstrap specific attributes #}
{%- set attributes = attributes|merge({'dropdown': null, 'divider_prepend': null, 'divider_append': null }) %}
{%- if divider_prepend %}
{{ block('dividerElement') }}
{%- endif %}
{# building the class of the item #}
{%- set classes = item.attribute('class') is not empty ? [item.attribute('class'), 'nav-item'] : ['nav-item'] %}
{%- if matcher.isCurrent(item) %}
{%- set classes = classes|merge([options.currentClass]) %}
{%- elseif matcher.isAncestor(item, options.depth) %}
{%- set classes = classes|merge([options.ancestorClass]) %}
{%- endif %}
{%- if item.actsLikeFirst %}
{%- set classes = classes|merge([options.firstClass]) %}
{%- endif %}
{%- if item.actsLikeLast %}
{%- set classes = classes|merge([options.lastClass]) %}
{%- endif %}
{# building the class of the children #}
{%- set childrenClasses = item.childrenAttribute('class') is not empty ? [item.childrenAttribute('class')] : [] %}
{%- set childrenClasses = childrenClasses|merge(['menu_level_' ~ item.level]) %}
{# adding classes for dropdown #}
{%- if is_dropdown %}
{%- set classes = classes|merge(['dropdown']) %}
{%- set childrenClasses = childrenClasses|merge(['dropdown-menu']) %}
{%- endif %}
{# putting classes together #}
{%- if classes is not empty %}
{%- set attributes = attributes|merge({'class': classes|join(' ')}) %}
{%- endif %}
{%- set listAttributes = item.childrenAttributes|merge({'class': childrenClasses|join(' ') }) %}
<li{{ macros.attributes(attributes) }}>
{# displaying the item #}
{%- if is_dropdown %}
{{ block('dropdownElement') }}
{%- elseif item.uri is not empty and (not item.current or options.currentAsLink) %}
{{ block('linkElement') }}
{%- else %}
{{ block('spanElement') }}
{%- endif %}
{%- if divider_append %}
{{ block('dividerElement') }}
{%- endif %}
{% if item.hasChildren and options.depth is not same as(0) and item.displayChildren %}
{{ block('dropdownlinks') }}
{% endif %}
</li>
{% endif %}
{% endblock %}
{% block dropdownlinks %}
{% if use_multilevel %}
<ul class="dropdown-menu">
{% else %}
<div class="dropdown-menu">
{% endif %}
{% for item in item.children %}
{{ block('renderDropdownlink') }}
{% if use_multilevel and item.hasChildren and options.depth is not same as(0) and item.displayChildren %}
{{ block('dropdownlinks') }}
{% endif %}
{% endfor %}
{% if not use_multilevel %}
</div>
{% else %}
</ul>
{% endif %}
{% endblock %}
{% block renderDropdownlink %}
{% import _self as ownmacro %}
{%- set divider_prepend = item.attributes.divider_prepend|default(false) %}
{%- set divider_append = item.attributes.divider_append|default(false) %}
{%- set attributes = item.attributes|merge({'dropdown': null, 'divider_prepend': null, 'divider_append': null }) %}
{% if use_multilevel %}
<li>
{% endif %}
{%- if divider_prepend %}
{{ block('dividerElementDropdown') }}
{%- endif %}
{%- if item.uri is not empty and (not item.current or options.currentAsLink) %}
{{ ownmacro.setCssClassAttribute(item, 'LinkAttribute', 'dropdown-item') }}
{{ block('linkElement') }}
{%- else %}
{{ block('spanElementDropdown') }}
{%- endif %}
{%- if divider_append %}
{{ block('dividerElementDropdown') }}
{%- endif %}
{% if use_multilevel %}
</li>
{% endif %}
{% endblock %}
{% block spanElementDropdown %}
{% import "knp_menu.html.twig" as macros %}
{% import _self as ownmacro %}
{{ ownmacro.setCssClassAttribute(item, 'LabelAttribute', 'dropdown-header') }}
<div {{ macros.attributes(item.labelAttributes) }}>
{% if item.attribute('icon') is not empty %}
<i class="{{ item.attribute('icon') }}"></i>
{% endif %}
{{ block('label') }}
</div>
{% endblock %}
{% block dividerElementDropdown %}
<div class="dropdown-divider"></div>
{% endblock %}
{% block dividerElement %}
{% if item.level == 1 %}
<li class="divider-vertical"></li>
{% else %}
<li class="divider"></li>
{% endif %}
{% endblock %}
{% block linkElement %}
{% import "knp_menu.html.twig" as macros %}
{% import _self as ownmacro %}
{{ ownmacro.setCssClassAttribute(item, 'LinkAttribute', 'nav-link') }}
<a href="{{ item.uri }}"{{ macros.attributes(item.linkAttributes) }}>
{% if item.attribute('icon') is not empty %}
<i class="{{ item.attribute('icon') }}"></i>
{% endif %}
{{ block('label') }}
</a>
{% endblock %}
{% block spanElement %}
{% import "knp_menu.html.twig" as macros %}
{% import _self as ownmacro %}
{{ ownmacro.setCssClassAttribute(item, 'LabelAttribute', 'navbar-text') }}
<span {{ macros.attributes(item.labelAttributes) }}>
{% if item.attribute('icon') is not empty %}
<i class="{{ item.attribute('icon') }}"></i>
{% endif %}
{{ block('label') }}
</span>
{% endblock %}
{% block dropdownElement %}
{% import "knp_menu.html.twig" as macros %}
{%- set classes = item.linkAttribute('class') is not empty ? [item.linkAttribute('class')] : [] %}
{%- set classes = classes|merge(['dropdown-toggle', 'nav-link']) %}
{%- set attributes = item.linkAttributes %}
{%- set attributes = attributes|merge({'class': classes|join(' ')}) %}
{%- set attributes = attributes|merge({'data-toggle': 'dropdown'}) %}
<a href="#"{{ macros.attributes(attributes) }}>
{% if item.attribute('icon') is not empty %}
<i class="{{ item.attribute('icon') }}"></i>
{% endif %}
{{ block('label') }}
<b class="caret"></b>
</a>
{% endblock %}
{% block label %}{{ item.label|trans }}{% endblock %}
仅包含菜单渲染模板后:
{{ knp_menu_render('AppBundle:Builder:mainMenu', {
'currentClass': 'active',
'template': 'extended_knp_menu.html.twig'
}) }}
希望对你有所帮助。