Как реализовать навигацию по "выбранному" пункту
Мне нужно реализовать навигационное меню на веб-странице, возможно, с несколькими уровнями вкладок. Я использовал способ CSS всякий раз, когда CSS находится под моим контролем, но теперь я сталкиваюсь с проблемами при использовании существующей библиотеки CSS (в данном случае Bootstrap Twitter).
Во-первых, это способ CSS, который я использовал. Пример HTML:
<html>
<head>
<title>Example page</title>
</head>
<body class="articles">
<div class="navigation">
<ul>
<li class="frontpage"><a href="#">Frontpage</a></li>
<li class="articles"><a href="#">Articles</a></li>
</ul>
</div>
<p>Blah blah.</p>
</body>
</html>
... и CSS:
body.frontpage div.navigation li.frontpage,
body.articles div.navigation li.articles {
background-color:red;
color:white;
}
Достаточно просто. Только класс тела должен был быть изменен при обучении.
Теперь Bootstrap, похоже, использует стиль на основе классов для выбора элементов навигации (верхняя панель, вкладки, таблетки). Пример:
...
<div class="navigation">
<ul class="tabs">
<li class="active"><a href="#">Frontpage</a></li>
<li><a href="#">Articles</a></li>
</ul>
</div>
...
Я изначально думал сделать что-то вроде
navigation = ('frontpage',)
# or
navigation = ('articles', 'categories', 'foo',)
в контроллере, а затем передать этот кортеж шаблонам, но каким-то образом у него есть такая атмосфера "делать это неправильно".
Таким образом, вопрос заключается в следующем: поскольку мне действительно нужно печатать выбор класса в шаблонах, как мне отслеживать текущее местоположение (например, где в дереве навигации находится эта страница), учитывая, что страница может иметь несколько уровней вкладки или другие элементы навигации? Есть ли предпочтительный способ сделать это?
Я использую Pyramid в стиле маршрута с шаблонами Mako, но общие ответы также приветствуются.
2 ответа
Я делаю нечто подобное (также Pyramid & Bootstrap), но только для одного уровня навигации.
Первым делом я создал объект "view", который передает параметры для каждого рендера, такого как title, header, get_data и т. Д. Пример.
class View_Controller(object):
def __init__(self, request, **kwargs):
self.request = request
self.nav = kwargs.get('nav', None)
@property
def page(self):
return request.GET.get('page', 1)
@view_config(route_name='home', renderer='templates/homepage.mako')
def Homepage_View(request):
view = View_Controller(request, nav='homepage')
stuff = DBSession.query(Stuff).all()
return {'view': view, 'stuff': stuff}
Я устанавливаю атрибут nav в каждой странице рендеринга, но имею nav = None, когда никакой элемент навигации не активирован Затем я создал шаблон для элементов навигации в Мако:
<%def name="navelements(things)">
% for a in things:
<li${' class="active"' if nav == a[1] else '' | n }><a href="#">a[0]</a></li>
% endfor
</%def>
Где "вещи" - это кортеж всех элементов навигации. [0] - это отображаемое имя, а [1] - внутреннее имя. "| N" необходим для экранирования символов html. Пример:
<%! things = [['Frontpage', 'homepage'], ['Articles', 'arts'], ['Categories', 'cats'], ['Foo', 'foo']] %>
% if things:
<div class="navigation">
<ul class="tabs">
${navelements(things)}
</ul>
</div>
% else:
<hr />
% endif
Теперь вы можете установить вещи либо в шаблоне, либо в контроллере через представление. У меня есть предложение "если что-то", если вам нужен универсальный шаблон вкладки, который вызывается на каждой странице; Вы можете отключить вкладки, просто установив вещи = Нет в контроллере.
Это только один уровень вкладок, но вы можете сделать то же самое, сделав список более сложным. Я бы все усложнил, чтобы по сравнению с тем, как он выглядит сейчас, это будет выглядеть так:
things = [['displayname1', 'elementname1', things1], ['displayname2', 'elementname2', things2], ...]
Затем я бы сделал рекурсивные navelements (которые Мако не поддерживает, поэтому я просто сделал бы две копии функции navelements и заставил бы их вызывать друг друга) и реализовал поддержку нескольких уровней nav:
<%def name="navelements1(things, level=0)">
% for a in things:
<li${' class="active"' if nav[level] == a[1] else '' | n }><a href="#">a[0]</a></li>
% if a[2]:
<ul class="tabs">
${navelements2(a[2], level+=1)}
</ul>
% endif
% endfor
</%def>
Где nav выглядит примерно так:
nav = ['frontpage', 'best', None, ...]
Надеюсь это ответит на твой вопрос. Просто убедитесь, что ваши списки имеют правильную длину, чтобы избежать ошибок.
Вы можете использовать системные значения, используемые во время рендеринга, чтобы получить имя представления в шаблоне путем доступа к переменной view.__name__
,
Затем измените активную ссылку на (пример в jinja2, но она должна быть похожей)
<li {% if view.__name__ == "fixtures" %} class="active" {% endif %}>
<a href="#">Link</a>
</li>
Более подробная информация на http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/templates.html