#php #symfony #twig
#php #symfony #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>
Комментарии:
1. Вы могли бы использовать
:first-child
и:last-child
псевдоклассы. В наши дни они широко поддерживаются.2. Вы также можете использовать IE7-js для добавления поддержки CSS3 в некоторые устаревшие IE.
3. Просто небольшое замечание; Я только что исправил ошибку, в которой я инвертировал параметры for .
Ответ №1:
Вы можете использовать «специальные переменные» 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 %}
Комментарии:
1. Возможно, я ошибаюсь, я новичок в Twig, но если массив содержит только один элемент
if
, оба оператора будут выполнены, что приведет кclass="topmenu-button first last
. В этом случае вы должны использоватьif...else
. Но, как я уже сказал, я могу ошибаться.2. В общем, мы также можем использовать что-то вроде этого: последний ? ‘последний’ }} «>
Ответ №2:
Поскольку цикл не может быть first
и last
одновременно, я бы предпочел не использовать elseif
и не писать (DRY — что, если вам придется меняться 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: это не будет обрабатывать массив из 1 элемента (первый = последний)
Комментарии:
1. Раньше я пытался кодировать HTML (и twig) подобным образом, но, честно говоря, ваше «более краткое» решение выглядит намного более шумным, а в предыдущем примере больше кода для установки переменной, чем в основной части
<div>
вашей печати. Такой заманчивый язык, как TWIG, на самом деле не подходит для идеального соответствия DRY, поскольку весь «код» должен быть экранирован{%
/%}
.2. @KendallHopkins Я согласен с тем, что вы говорите о сжатом коде, я всегда буду использовать первый. ИМХО, лучше написать больше кода для установки переменной, а не повторять
div
объявление иclass
атрибут 3 раза. С таким количеством повторений, как у вас, изменение чего-либо будет действительно болезненным (и пустой тратой времени и денег). Плюсelseif
иelse
выглядит ужасно для меня.3. Посмотрев на эту проблему еще раз, я думаю, что мы оба ошибаемся. Мы забываем «один» случай, когда вы можете иметь
class="topmenu-button first last"
. Учитывая эту дополнительную сложность, я думаю, что лучше всего будет обработатьmerge
filter и разбить его на собственную переменную, аналогичную тому, как вы это делаете. Я обновил свой ответ, WDYT?4. @KendallHopkins ты чертовски прав. 1 для вас, мне нравится ваш (второй) подход в вашей правке. Однако я бы инвертировал
loop.first
иloop-last
проверил, поскольку первый и единственный элемент массива должен рассматриваться и стилизоваться как первый. Но это зависит от него.
Ответ №3:
Если это для управления атрибутом класса тега, троичное условие было бы лучше.
<span class="topmenu-button {{ (loop.first) ? 'first' : '' }}">{{ item.text }}</span>
Ответ №4:
Я использую это в шаблоне представлений 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 %}