Статьи

Создание динамических адаптивных многоуровневых меню с простым HTML и OmniFaces

Недавно мне пришлось создать адаптивное многоуровневое меню с помощью JSF 2.2. Требования: меню должно:

  • быть создан с динамической структурой из бэкэнда
  • быть отзывчивым, то есть настольным и мобильным
  • есть элементы подменю с навигационными ссылками
  • поддержка сенсорных событий
  • поддержка доступа к клавиатуре

Меню PrimeFaces не было выбора. Они действительно могут быть созданы программно по модели, но:

  • они не очень отзывчивы
  • Элементы подменю только сворачивают / раскрывают подменю и не могут содержать навигационные ссылки

Ну, а почему бы не выбрать какой-либо плагин на основе jQuery для адаптивных многоуровневых меню? Есть много плагинов. См. Полезный список адаптивных шаблонов навигации и меню . Я выбрал FlexNav .

Но как вывести динамическую структуру меню? ui: повторение здесь не является выбором, потому что структура (вложенные подменю и т. д.) априори не известна. К счастью, есть OmniFaces с o: tree , который позволяет полностью контролировать разметку иерархии дерева, объявляя компоненты JSF или элементы HTML в разметке. o: дерево само по себе не отображает HTML-разметку. Именно то, что мне нужно!

Я закончил с этим XHTML-фрагментом, смешивающим элементы o: treeNode, o: treeNodeItem, o: treeInsertChildren и HTML, определенные в упомянутом меню FlexNav:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<h:outputScript library="js" name="jquery.flexnav.js"/>
<h:outputStylesheet library="css" name="flexnav.css"/>
 
<ul id="mainnavi" class="flexnav" data-breakpoint="640" role="navigation">
    <o:tree value="#{mainNavigationBean.treeModel}" var="item">
        <o:treeNode level="0">
            <o:treeNodeItem>
                <li class="item">
                    <a href="#{item.href}" title="#{item.title}">#{item.text}</a>
                    <o:treeInsertChildren/>
                </li>
            </o:treeNodeItem>
        </o:treeNode>
        <o:treeNode>
            <ul>
                <o:treeNodeItem>
                    <li>
                        <a href="#{item.href}" title="#{item.title}">#{item.text}</a>
                        <o:treeInsertChildren/>
                    </li>
                </o:treeNodeItem>
            </ul>
        </o:treeNode>
    </o:tree>
</ul>
 
<h:outputScript id="mainnaviScript" target="body">
    $(document).ready(function () {
        $("#mainnavi").flexNav({'calcItemWidths': true});
    });
</h:outputScript>

TreeModel OmniFaces с элементами меню создается программно. Код Java выглядит следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
public TreeModel<NavigationItemDTO> getTreeModel() {
    // get menu model from a remote service
    NavigationContainerDTO rootContainer = remoteService.fetchMainNavigation(...);
 
    TreeModel<NavigationItemDTO> treeModel = new ListTreeModel<>();
    buildTreeModel(treeModel, rootContainer.getNavItem());
 
    return treeModel;
}
 
private void buildTreeModel(TreeModel<NavigationItemDTO> treeModel, List<NavigationItemDTO> items) {
    for (NavigationItemDTO item : items) {
        buildTreeModel(treeModel.addChild(item), item.getNavItem());
    }
}

И конечный результат (настольный вариант):

responsiveMenu

Обратите внимание, что подменю доступны для нажатия и могут быть расширены при наведении курсора мыши.

Видите ли, JSF является гибким, и иногда вам не нужны полноценные компоненты. Повеселись!