For loop,将每两篇文章包装在一个div中

26
基本上,我正在使用Jekyll(它使用Liquid模板语言),我正在尝试编写一个for循环,将每两个项目包装在一个div中。
这是我的当前循环:
<div>
  {% for post in site.posts %}
    <a href="{{ post.url }}">{{ post.title }}</a>
  {% endfor %}
</div>

这将输出四篇文章,如下所示:

<div>
  <a href="#">Title</a>
  <a href="#">Title</a>
  <a href="#">Title</a>
  <a href="#">Title</a>
</div>

我期望的输出是四篇文章:

<div>
  <a href="#">Title</a>
  <a href="#">Title</a>
</div>

<div>
  <a href="#">Title</a>
  <a href="#">Title</a>
</div>

我该如何完成这个任务?


你想用一个div包裹每个链接吗? - Asad Ullah
@AsadMalik:不是的。请查看更新后的帖子,我想要每两个帖子链接都包含在“div”中。 - Tom
9个回答

35
如果
的数量和文章数量是固定的(根据您选择的答案似乎是这种情况),则可以使用limit和offset来以较短的方式获得相同的输出:
(Liquid分页的方法)
<div>
  {% for post in site.posts limit: 2 %}
    <a href="{{ post.url }}">{{ post.title }}</a>
  {% endfor %}
</div>
<div>
  {% for post in site.posts limit: 2 offset: 2 %}
    <a href="{{ post.url }}">{{ post.title }}</a>
  {% endfor %}
</div>

更好的解决方案:

如果文章数量不固定 (例如当你有100篇文章时,你想要50个<div>,每个中包含两篇文章),那么你可以使用forloop.index(这已经在大多数其他答案中提到了),并使用modulo 判断当前索引是偶数还是奇数:

{% for post in site.posts %}
  {% assign loopindex = forloop.index | modulo: 2 %}
  {% if loopindex == 1 %}
    <div>
      <a href="{{ post.url }}">{{ post.title }}</a>
  {% else %}
      <a href="{{ post.url }}">{{ post.title }}</a>
    </div>
  {% endif %}
{% endfor %}

这个方法返回你想要的输出,而且适用于任何数量的文章。


1
非常感谢您的帮助,虽然我没有使用您提供的确切答案,但是研究“模数”函数让我找到了这里(https://gist.github.com/leemachin/2366832),这是一个非常好的方法,适用于我正在尝试做的事情,我将发布我的更新代码的另一个答案。 - Tom
5
这是否漏了一个 </div>,导致网站文章数量不匹配? - P3trus

22

我知道我来晚了,但我找到了一个相当优雅的解决方案,感觉不像是hacky。

通过for循环的limitoffset参数,我们可以每次迭代一行,每行N个帖子。

首先,我们计算需要枚举的行数:

{% assign rows = site.posts.size | divided_by: 2.0 | ceil %}

在 Ruby 中等价的代码为 rows = (posts.size / 2.0).ceil(奇数会分到自己的一行)。

接下来,我们将遍历这些行:

{% for i in (1..rows) %}
  <div>

现在我们需要使用 forloop.index0 计算集合的偏移量:(i - 1) * 2

  {% assign offset = forloop.index0 | times: 2 %}

然后,我们可以迭代遍历帖子片段,该片段从行偏移开始(相当于 Ruby 中的 posts[offset, 2]):

    {% for post in site.posts limit:2 offset:offset %}
      <a href="{{ post.url }}">{{ post.title }}</a>
    {% endfor %}

关闭行的 div 元素并结束循环:

  </div>
{% endfor %}

就是这样了!

在 Ruby 中,这将是:

rows = (posts.size / 2.0).ceil # the number of rows
(1..rows).each do |i|
  offset = (i - 1) * 2
  # <div>
  posts[offset, 2].each do |post|
    # <a href="#{post.url}>#{post.title}</a>
  end
  # </div>
end

现在,全部在 Liquid 中:

{% assign rows = site.posts.size | divided_by: 2.0 | ceil %}
{% for i in (1..rows) %}
  {% assign offset = forloop.index0 | times: 2 %}
  <div>
    {% for post in site.posts limit:2 offset:offset %}
      <a href="{{ post.url }}">{{ post.title }}</a>
    {% endfor %}
  </div>
{% endfor %}

希望这能帮到某些人!


6
尝试这个:

试试看这个:

<div>
    {% for post in paginator.posts %}
        <div>
            {% if forloop.index == 1 %}
                <a href="">{{ post.title }}</a>
            {% endif %}
            {% if forloop.index == 2 %}
                <a href="">{{ post.title }}</a>
            {% endif %}
        </div>
        <div>
            {% if forloop.index == 3 %}
                <a href="">{{ post.title }}</a>
            {% endif %}
            {% if forloop.index == 4 %}
                <a href="">{{ post.title }}</a>
            {% endif %}
        </div>
    {% endfor %}
</div>

我不得不将一些实例 {% endfor %} 替换为 {% endif %},以避免出现错误,但恐怕它仍然无法正常工作,它会产生以下输出 http://pastebin.com/Kt8gA3nw。不过,我真的很感激你的帮助 :) - Tom

6

我刚刚发现这个(https://gist.github.com/leemachin/2366832),相比其他回答中发布的解决方案,这是一个更好的解决方案。请注意,您需要此插件(https://gist.github.com/leemachin/2366832#file-modulo-filter-rb)才能使其正常工作:

{% for post in paginator.posts %}

  {% capture modulo %}{{ forloop.index0 | mod:2 }}{% endcapture %}

  {% if modulo == '0' or forloop.first %}
    <div>
  {% endif %}

    <a href="{{ post.url }}">{{ post.title }}</a>

  {% if modulo == '1' or forloop.last %}
    </div>
  {% endif %}

{% endfor %}

2

我真应该集中精力做事情,但一岁的孩子总是给我她所有的玩具... :D

代码现在应该可以正常工作:

<div>
    <div>
        {% for post in paginator.posts %}
            {% if forloop.index == 1 %}
                <a href="">{{ post.title }}</a>
            {% endif %}
            {% if forloop.index == 2 %}
                <a href="">{{ post.title }}</a>
            {% endif %}
        {% endfor %}
    </div>
    <div>
        {% for post in paginator.posts %}
            {% if forloop.index == 3 %}
                <a href="">{{ post.title }}</a>
            {% endif %}
            {% if forloop.index == 4 %}
                <a href="">{{ post.title }}</a>
            {% endif %}
        {% endfor %}
    </div>
</div>

应该提供以下html:

<div>
    <div>
        <a href="">Title 1</a>
        <a href="">Title 2</a>
    </div>
    <div>
        <a href="">Title 3</a>
        <a href="">Title 4</a>
    </div>
</div>

成功了!你太棒了,我接下来会在这篇文章中更新最终代码,再次感谢你! - Tom

1

在查看了Christian的解决方案后,我更新了我的(基于pug的)代码:

.blog
    .container
        .row
            .col-xs-0
            .col-xs-12
                h1 Blog
                p Summit blog with latest news, thinking and participant's posts.
            .col-xs-0
        | {% for page in site.posts                         %}
        | {% assign loopindex = forloop.index | modulo: 2   %}
        | {% if loopindex == 1                              %}
        .row
        | {% endif %}
        span
            .col-xs-6.col-sm-6
                .card
                    .card-top
                        + add-title
                        + add-author
                    .card-block
                        + add-snippet
        | {% endfor                                        %}

0

您可以使用 cycle 标签来实现此操作,如 https://shopify.github.io/liquid/tags/iteration/ 中所述。

{% for post in site.posts %}
  {% cycle '<div>', '' %}
    <a href="{{ post.url }}">{{ post.title }}</a>
  {% cycle '', '</div>' %}
{% endfor %}

输出

<div>
  <a href="#">Title</a>
  <a href="#">Title</a>
</div>

<div>
  <a href="#">Title</a>
  <a href="#">Title</a>
</div>

0

好的,我已经快速尝试了一下,虽然没有适当的样式,但这应该可以工作:

<div>
{% for post in paginator.posts %}
    {% case forloop.index %}
    <div>
    {% when 1 %}
        <a href="">{{ post.title }}</a>
    {% when 2 %}
        <a href="">{{ post.title }}</a>
    </div>
    <div>
    {% when 3 %}
        <a href="">{{ post.title }}</a>
    {% when 4 %}
        <a href="">{{ post.title }}</a>
    </div>
{% endcase %}
{% endfor %}
</div>

虽然代码不是最好的,但我自己也是刚接触jekyll,尝试这样的东西很难,因为(据我所知)这种特定的操作不是很容易解决的问题,但是如果你要每页显示四篇文章,这应该可以通过分页来实现...虽然我还没有测试过这个理论,但我应该会去做... - Nigel Greenway
非常感谢您的帮助,但我认为使用这个会遇到问题。它假设每个页面上都恰好有四篇文章,但事实并非如此。例如,当我只有少于4篇已发布的文章时,或者我有像7篇已发布的文章这样的情况;第一页将有4篇文章,但第二页将有3篇文章,这将导致无效的HTML,因为缺少一个</div>。显然,您在Jekyll循环方面比我更有经验,因为我来自WordPress背景,习惯于像http://bit.ly/1f3vIqw这样的操作,是否有任何方法可以模仿这个? - Tom

0

在@smilinmonki666的帮助下,我已经让它按照我的意愿工作了,这是我最终采用的代码:

{% assign current_page_posts = paginator.posts | size %}

{% if current_page_posts > 0 %}
  <div>

    <div>
      {% for post in paginator.posts %}
        {% if forloop.index == 1 %}
          <a href="{{ post.url }}">{{ post.title }}</a>
        {% endif %}

        {% if forloop.index == 2 %}
          <a href="{{ post.url }}">{{ post.title }}</a>
        {% endif %}
      {% endfor %}
    </div>

    {% if current_page_posts > 2 %}
      <div>
        {% for post in paginator.posts %}
          {% if forloop.index == 3 %}
            <a href="{{ post.url }}">{{ post.title }}</a>
          {% endif %}

          {% if forloop.index == 4 %}
            <a href="{{ post.url }}">{{ post.title }}</a>
          {% endif %}
        {% endfor %}
      </div>
    {% endif %}

  </div>
{% endif %}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接