Twig, добавьте первый и последний класс

Допустим, у меня есть такой цикл for:

{% for elem in arrMenu %}
    <div class="topmenu-button">
        <a href="{{ elem.url }}">{{ elem.name }}</a>
    </div>
{% endfor %}

В таком виде это будет выглядеть примерно так:

<div class="topmenu-button"><a href="url">name</a></div>
<div class="topmenu-button"><a href="url">name</a></div>
<div class="topmenu-button"><a href="url">name</a></div>
<div class="topmenu-button"><a href="url">name</a></div>

Как twig может помочь мне добавить первый и последний классы в div, чтобы у меня был такой результат:

<div class="topmenu-button first"><a href="url">name</a></div>
<div class="topmenu-button"><a href="url">name</a></div>
<div class="topmenu-button"><a href="url">name</a></div>
<div class="topmenu-button last"><a href="url">name</a></div>

person FMaz008    schedule 20.10.2011    source источник
comment
Вы можете использовать псевдоклассы :first-child и :last-child. Те дико поддерживаются в эти дни.   -  person Crozin    schedule 20.10.2011
comment
Вы также можете использовать IE7-js, чтобы добавить поддержку CSS3 в некоторые устаревшие версии IE.   -  person Kendall Hopkins    schedule 20.10.2011
comment
Просто быстрое примечание; Я только что исправил ошибку, когда инвертировал параметры for.   -  person FMaz008    schedule 20.10.2011


Ответы (4)


Вы можете использовать «специальные переменные» loop.first и loop.last для того, что хотите.

ССЫЛКА

{% for elem in arrMenu %}
    {% if loop.first %}
    <div class="topmenu-button first">        
    {% elseif loop.last %}
    <div class="topmenu-button last">        
    {% else %}
    <div class="topmenu-button">        
    {% endif %}
        <a href="{{ elem.url }}">{{ elem.name }}</a>
    </div>
{% endfor %}

РЕДАКТИРОВАТЬ: в зависимости от того, насколько вы заботитесь об «одном случае», вам может понадобиться такое решение.

{% for elem in arrMenu %}
    {% set classes = ["topmenu-button"] %}
    {% if loop.first %}{% set classes = classes|merge(["first"]) %}{% endif %}
    {% if loop.last %}{% set classes = classes|merge(["last"]) %}{% endif %}
    <div class="{{ classes|join(" ") }}">        
        <a href="{{ elem.url }}">{{ elem.name }}</a>
    </div>
{% endfor %}
person Kendall Hopkins    schedule 20.10.2011
comment
Возможно, я ошибаюсь, я новичок в Twig, но если массив содержит только один элемент, будут выполнены оба оператора if, что приведет к class="topmenu-button first last. В этом случае вы должны использовать if...else. Но, как я уже сказал, я могу ошибаться. - person gremo; 21.10.2011

Поскольку цикл не может быть first и last одновременно, я бы предпочел не использовать elseif и написать (СУХОЙ - что, если вам придется изменить topmenu-button в будущем?):

{% for elem in arrMenu %}
    {% set append %}
        {% if loop.first %}first{% endif %}
        {% if loop.last %}last{% endif %}
    {% endset %}
    <div class="topmenu-button {{ append }}">
        <a href="{{ elem.url }}">{{ elem.name }}</a>
    </div>
{% endfor %}

или более кратко:

{% for elem in arrMenu %}
    <div class="topmenu-button {% if loop.first %}first{% endif %} {% if loop.last %}last{% endif %}">
        <a href="{{ elem.url }}">{{ elem.name }}</a>
    </div>
{% endfor %}

Редактировать: таким образом вы получите дополнительные пробелы в атрибуте class (кстати, это совершенно нормально). Edit2: это не будет обрабатывать одноэлементный массив (первый = последний)

person gremo    schedule 20.10.2011
comment
Раньше я пытался кодировать HTML (и ветку) таким образом, но, честно говоря, ваше более лаконичное решение выглядит намного более зашумленным, а в предыдущем примере больше кода для установки переменной, чем основной текст <div> вашей печати. Заманчивый язык, такой как TWIG, на самом деле не подходит для идеального соответствия DRY, поскольку весь код должен экранироваться с помощью {%/%}. - person Kendall Hopkins; 21.10.2011
comment
@KendallHopkins Я согласен с тем, что вы говорите о кратком коде, я всегда буду использовать первый. ИМХО, лучше написать больше кода для установки переменной, чем повторять объявление div и атрибут class 3 раза. С кучей повторений, как у вас, что-то изменить будет действительно мучительно (и пустой тратой времени и денег). К тому же elseif и else мне кажутся ужасными. - person gremo; 21.10.2011
comment
Посмотрев на эту проблему еще раз, я думаю, что мы оба не правы. Мы забываем об одном случае, когда вы можете иметь class="topmenu-button first last". Учитывая эту дополнительную сложность, я думаю, что мне лучше всего справиться с фильтром merge и разбить его на собственную переменную, аналогичную тому, как вы это делаете. Я обновил свой ответ, WDYT? - person Kendall Hopkins; 21.10.2011
comment
@KendallHopkins, ты чертовски прав. +1 для вас, мне нравится ваш (второй) подход в вашем редактировании. Однако я бы инвертировал проверки loop.first и loop-last, так как первый и единственный элемент массива должен рассматриваться и стилизоваться как первый. Но это зависит от него. - person gremo; 21.10.2011

Если нужно управлять атрибутом класса тега, лучше использовать троичное условие.

<span class="topmenu-button {{ (loop.first) ? 'first' : '' }}">{{ item.text }}</span>
person Paul Leclerc    schedule 06.12.2016

Я использую это в шаблоне представлений Drupal 8. Спасибо за «elseif», если у вас есть только 1 элемент, то первый элемент никогда не получит «последний» класс:

{% for row in rows %}
    {% set parity = cycle(['odd', 'even'], loop.index0) %}
    {% set row_classes = [ default_row_class ? 'views-row', ] %}    

    <div class="views-prerow {{parity}}{% if loop.first %} first{% elseif loop.last %} last{% endif %}">
        <div{{ row.attributes.addClass(row_classes) }}>
            {{ row.content }}
        </div>
    </div>
{% endfor %}
person Gódi Péter    schedule 01.03.2018