Как сделать меню с одним активным элементом с СУХОЙ? - PullRequest
39 голосов
/ 20 марта 2012

Я хотел бы сделать такие конструкции, как:

<a href='/home'>Home</a>
<span class='active'>Community</span>
<a href='/about'>About</a>

Где Сообщество - выбранный пункт меню. У меня есть меню с одинаковыми параметрами для нескольких шаблонов, но я не хотел бы создавать комбинации для каждого шаблона:

<!-- for Home template-->
        <span class='active'>Home</span>
        <a href='/comminuty'>Community</a>
        <a href='/about'>About</a>
    ...
<!-- for Community template-->
        <a href='/home'>Home</a>
        <span class='active'>Community</span>
        <a href='/about'>About</a>
    ...
<!-- for About template-->
        <a href='/home'>Home</a>
        <a href='/community'>Community</a>
        <span class='active'>About</span>

У нас есть постоянный список пунктов меню, так что это может быть более эффективным способом - создать только одну обобщенную структуру меню, а затем отобразить меню с необходимой опцией для шаблона.

Например, это может быть тег, который позволяет это сделать.

Ответы [ 10 ]

65 голосов
/ 09 декабря 2014

Придумал еще один способ сделать это, достаточно элегантно благодаря этому ответу: https://stackoverflow.com/a/17614086/34871

Учитывая шаблон URL, такой как:

url(r'^some-url', "myapp.myview", name='my_view_name'),

my_view_name доступно для шаблона через request (помните, что вам нужно использовать RequestContext - что подразумевается при использовании render_to_response)

Тогда пункты меню могут выглядеть так:

<li class="{% if request.resolver_match.url_name == "my_view_name" %}active{% endif %}"><a href="{% url "my_view_name" %}">Shortcut1</a></li>
<li class="{% if request.resolver_match.url_name == "my_view_name2" %}active{% endif %}"><a href="{% url "my_view_name2" %}">Shortcut2</a></li>

и т.д.

Таким образом, URL может измениться, и он все еще работает, если параметры URL изменяются, и вам не нужно хранить список пунктов меню где-либо еще.

49 голосов
/ 12 сентября 2013

Использование тега шаблона

Вы можете просто использовать следующий тег шаблона:

# path/to/templatetags/mytags.py
import re

from django import template
try:
    from django.urls import reverse, NoReverseMatch
except ImportError:
    from django.core.urlresolvers import reverse, NoReverseMatch

register = template.Library()


@register.simple_tag(takes_context=True)
def active(context, pattern_or_urlname):
    try:
        pattern = '^' + reverse(pattern_or_urlname)
    except NoReverseMatch:
        pattern = pattern_or_urlname
    path = context['request'].path
    if re.search(pattern, path):
        return 'active'
    return ''

Итак, у вас ваш шаблон:

{% load mytags %}
<nav><ul>
  <li class="nav-home {% active 'url-name' %}"><a href="#">Home</a></li>
  <li class="nav-blog {% active '^/regex/' %}"><a href="#">Blog</a></li>
</ul></nav>

Использование только HTML &CSS

Существует другой подход, использующий только HTML и CSS, который вы можете использовать в любых фреймворках или статических сайтах.

Учитывая, что у вас есть такое меню навигации:

<nav><ul>
  <li class="nav-home"><a href="#">Home</a></li>
  <li class="nav-blog"><a href="#">Blog</a></li>
  <li class="nav-contact"><a href="#">Contact</a></li>
</ul></nav>

Создайте несколько базовых шаблонов, по одному для каждой сессии вашего сайта, например:

home.html
base_blog.html
base_contact.html

Все эти шаблоны расширяют base.html с помощью block"section",как, например:

...
<body id="{% block section %}section-generic{% endblock %}">
...

Затем, взяв base_blog.html в качестве примера, вы должны иметь следующее:

{% extends "base.html" %}
{% block section %}section-blog{% endblock %}

Теперь легко определить пункт меню actived с помощью CSSтолько:

#section-home .nav-home,
  #section-blog .nav-blog,
  #section-contact .nav-contact { background-color: #ccc; }
29 голосов
/ 21 марта 2012

Я нашел простое и элегантное СУХОЕ решение.

Это фрагмент: http://djangosnippets.org/snippets/2421/

**Placed in templates/includes/tabs.html**

<ul class="tab-menu">
    <li class="{% if active_tab == 'tab1' %} active{% endif %}"><a href="#">Tab 1</a></li>
    <li class="{% if active_tab == 'tab2' %} active{% endif %}"><a href="#">Tab 2</a></li>
    <li class="{% if active_tab == 'tab3' %} active{% endif %}"><a href="#">Tab 3</a></li>
</ul>

**Placed in your page template**

{% include "includes/tabs.html" with active_tab='tab1' %}
4 голосов
/ 20 марта 2012

Вы можете создать контекстную переменную links с именем, URL и активным элементом:

{% for name, url, active in links %}
    {% if active %}
<span class='active'>{{ name }}</span>
    {% else %}
<a href='{{ url }}'>{{ name }}</a>
    {% endif %}
{% endfor %}

Если это меню присутствует на всех страницах, вы можете использовать контекстный процессор:

def menu_links(request):
    links = []
    # write code here to construct links
    return { 'links': links }

Затем в файле настроек добавьте эту функцию к TEMPLATE_CONTEXT_PROCESSORS следующим образом: path.to.where.that.function.is.located.menu_links. Это означает, что функция menu_links будет вызываться для каждого шаблона, а это означает, что переменная links доступна в каждом шаблоне.

2 голосов
/ 25 января 2018

Я нашел способ использовать теги блоков в родительском шаблоне, содержащем меню, для достижения чего-то подобного.

base.html - родительский шаблон:

<a href="/" class="{% block menu_home_class %}{% endblock %}">Home</a>
<a href="/about" class="{% block menu_about_class %}{% endblock %}">About</a>
<a href="/contact" class="{% block menu_contact_class %}{% endblock %}">Contact</a>

{% block content %}{% endblock %}

about.html - шаблон для конкретной страницы:

{% extends "base.html" %}

{% block menu_about_class %}active{% endblock %}

{% block content %}
    About page content...
{% endblock %}

Как видите, для разных шаблонов страниц различается имя блока, содержащего active.contact.html будет использовать menu_contact_class и т. Д.

Одним из преимуществ этого подхода является то, что вы можете иметь несколько подстраниц с одним и тем же активным пунктом меню.Например, страница about может иметь подстраницы, содержащие информацию о каждом члене команды компании.Может иметь смысл, чтобы пункт меню «О программе» оставался активным для каждой из этих подстраниц.

1 голос
/ 03 января 2019

Вот мое решение:

{% url 'module:list' as list_url %}
{% url 'module:create' as create_url %}

<ul>
    <li><a href="{% url 'module:list' %}" class="{% if request.path == list_url %}active{% endif %}">List Page</a></li>
    <li><a href="{% url 'module:create' %}" class="{% if request.path == create_url %}active{% endif %}">Creation Page</a></li>
</ul>
1 голос
/ 19 декабря 2014

Предполагая, что элемент навигации является ссылкой с тем же URL, что и текущая страница, вы можете просто использовать JavaScript. Вот аннотированный метод, который я использую, чтобы добавить class="active" к li в меню навигации с помощью class="nav":

// Get the path name (the part directly after the URL) and append a trailing slash
// For example, 'http://www.example.com/subpage1/sub-subpage/' 
//     would become '/subpage1/'
var pathName = '/' + window.location.pathname.split('/')[1];
if ( pathName != '/' ) { pathName = pathName + '/'; }

// Form the rest of the URL, so that we now have 'http://www.example.com/subpage1/'
// This returns a top-level nav item
var url = window.location.protocol + '//' +
          window.location.host +
          pathName;
console.log(url);

// Add an 'active' class to the navigation list item that contains this url
var $links = document.querySelectorAll('.nav a');
$link = Array.prototype.filter.call( $links, function(el) {
    return el.href === url;
})[0];
$link.parentNode.className += ' active';

Этот метод означает, что вы можете просто вставить его в базовый шаблон один раз и забыть о нем. Нет повторений и ручного указания URL страницы в каждом шаблоне.

Одно предостережение: очевидно, что это работает, только если найденный url соответствует навигационной ссылке href. Кроме того, можно было бы указать несколько особых случаев использования в JS или при необходимости настроить таргетинг на другой родительский элемент.

Вот пример работоспособного кода (имейте в виду, что фрагменты кода запускаются в StackSnippets):

// Get the path name (the part directly after the URL) and append a trailing slash
// For example, 'http://www.example.com/subpage1/sub-subpage/' 
//     would become '/subpage1/'
var pathName = '/' + window.location.pathname.split('/')[1];
if ( pathName != '/' ) { pathName = pathName + '/'; }

// Form the rest of the URL, so that we now have 'http://www.example.com/subpage1/'
// This returns a top-level nav item
var url = window.location.protocol + '//' +
          window.location.host +
          pathName;
console.log(url);

// Add an 'active' class to the navigation list item that contains this url
var $links = document.querySelectorAll('.nav a');
$link = Array.prototype.filter.call( $links, function(el) {
    return el.href === url;
})[0];
$link.parentNode.className += ' active';
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: black;
  text-decoration: none;
}
.active a {
  color: red;
}
<ul class="nav">
  <li>
    <a href="http://example.com/">Example Link</a>
  </li>
  <li>
    <a href="http://stacksnippets.net/js/">This Snippet</a>
  </li>
  <li>
    <a href="https://google.com/">Google</a>
  </li>
  <li>
    <a href="http://stackoverflow.com/">StackOverflow</a>
  </li>
</ul>
0 голосов
/ 21 октября 2016

Я использую более простое и чистое решение CSS. У него есть свои ограничения, о которых я знаю и с которыми можно жить, но он избегает неуклюжих селекторов класса CSS, например:

<a href="index.html" class="item{% if url == request.path %}active{% endif %}">index</a>

Поскольку пробел перед символом active отсутствует, селектор класса называется itemactive вместо item active, и это не так уж и сложно, ошибиться таким образом.

Для меня это чистое CSS-решение работает намного лучше:

a.item /* all menu items are of this class */
{
    color: black;
    text-decoration: none;
}

a.item[href~="{{ request.path }}"] /* just the one which is selected matches */
{
    color: red;
    text-decoration: underline;
}

Примечание: это работает даже в том случае, если в URL есть дополнительные компоненты пути, потому что тогда href также частично совпадает. Это может в конечном итоге привести к «коллизиям» с более чем одним совпадением, но достаточно часто это просто работает, потому что на хорошо структурированных веб-сайтах «подкаталог» URL-адреса обычно является дочерним элементом выбранного элемента меню.

0 голосов
/ 06 февраля 2016

Сегодня я столкнулся с этой проблемой, как динамически активировать «категорию» на боковой панели. В категориях есть слизни из БД.

Я решил это, проверив, что слаг категории был в текущем пути. Слизни уникальны (стандартная практика), поэтому я думаю, что это должно работать без каких-либо конфликтов.

{% if category.slug in request.path %}active{% endif %}

Полный пример кода цикла, чтобы получить категории и активировать текущую.

{% for category in categories %}
<a class="list-group-item {% if category.slug in request.path %}active{% endif %}" href="{% url 'help:category_index' category.slug %}">
  <span class="badge">{{ category.article_set.count }}</span>
  {{ category.title }}
</a>
{% endfor %}
0 голосов
/ 16 июля 2015

Основываясь на ответе @ vincent, есть более простой способ сделать это, не испортив шаблоны django url.

Текущий путь запроса можно проверить по отображенному пути элемента меню, и если они совпадают, то это активный элемент.

В следующем примере я использую django-mptt для рендеринга меню, но можно заменить node.path каждым путем к пункту меню.

<li class="{% if node.path == request.path %}active{% endif %}">
    <a href="node.path">node.title</a>
</li>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...