Ruby 的 Liquid 模板引擎中的模数(或缺少模数)
Posted
技术标签:
【中文标题】Ruby 的 Liquid 模板引擎中的模数(或缺少模数)【英文标题】:Modulus (or lack thereof) in Ruby's Liquid templating engine 【发布时间】:2011-01-15 19:14:25 【问题描述】:我在 Jekyll 网站上工作,并试图输出嵌套在行 div 中的三列 div。 Liquid 使用他们的 cycle
过滤器使这变得非常容易:
% for p in site.categories.post %
% cycle 'add rows': '<div class="row">', nil, nil %
<div class="column">
<a href=" p.url "> p.title </a>
</div>
% cycle 'close rows': nil, nil, '</div>' %
% endfor %
但是,这仅在有 3、6、9 等帖子时才真正有效。当帖子总数不是三的倍数时,<div class="row">
永远不会关闭——for 循环在结束标记可以作为close rows
循环的一部分输出之前结束。
在 Ruby、php 或任何其他语言中,我可以使用模数运算符轻松解决此问题,因此除了 close rows
循环之外,我会在 if site.categories.size % 3 == 0
时输出 </div>
。然而,Liquid,因为它是一种安全的模板语言,不支持模数。
当帖子总数不是三的倍数时,我还能做些什么来正确关闭<div class="row">
?
【问题讨论】:
【参考方案1】:我发现这种方法效果很好!
% assign mod = forloop.index0 | modulo:4 %
% if mod == 0 %
<!-- Do stuff -->
% endif %
【讨论】:
Modulo 一定是在以后的 Jekyll 版本中添加的。这绝对适用于我的项目。【参考方案2】:对于您的具体示例,您可以在% endfor %
之后使用% cycle 'close rows': nil, '</div>', '</div>' %
。
【讨论】:
【参考方案3】:目前唯一的方法是编写一个液体过滤器来实现这一点。在代码中适当的地方注册过滤器(如果使用 Rails 和没有 Rails,则在不同的地方)。
Liquid::Template.register_filter(LiquidFilters)
在你的项目/lib目录中添加liquid_filters.rb:
module LiquidFilters
# makes modulus operation available to templates
def mod(data, param)
data % param
end
end
之后,您可以在模板中使用它,如下所示: 变量 |模组:5
如果您需要将它用于某些逻辑,您可以捕获该值。
% capture modulus % variable | mod:5 % endcapture %
只是我注意到捕获的值是一个字符串,所以为了比较它你使用
% if modulus == "0" %
..
% endif %
【讨论】:
【参考方案4】:我在 for 循环中使用了另一个技巧:在你的情况下没用,如果你只是想要一个模数来确定你的行是否已经结束并且你需要一个新行,就像我一样。
在此示例中,我将使用一行 4 项:
% assign currentRow = 1 %
# enter the for loop ... then, with 4 as the divisor:
% if forloop.index == 4 * currentRow %
# do whatever you want
% assign currentRow = currentRow + 1 %
% endif %
# exit the for loop
不是很好,但很容易。
【讨论】:
【参考方案5】:我知道提问者的问题已经解决了,但我最近在 Liquid 中遇到了这种情况,我想我会提供我的解决方案,以防它可以帮助有类似标记要求的人。
在我的例子中,我已经通过了一个 if 语句来验证至少有一个帖子,所以我在循环之外创建了第一个“行”div。我也在 for 循环之后关闭它。这可以防止出现少于三个帖子的情况。
<div class="row">
% for p in posts %
<div class="column">
<!-- Post code here -->
</div>
% unless forloop.last %
% cycle '', '', '</div><div class="row">' %
% endunless %
% endfor %
</div>
每三个帖子后,循环将关闭当前行并打开一个新行unless
该帖子是forloop中的最后一个,在这种情况下我们不想打开一个新行,让包装 </div>
关闭它。
【讨论】:
【参考方案6】:我从这篇文章中学到了很多,这是我在整个项目中使用的三种模式。它也适用于 Bootstrap。只需更改以下代码中的列类。除了列,相同的模式可以应用于模数有用的其他场景,例如奇偶行。希望它可以帮助某人-
四列:
<div class="container">
% for post in site.posts %
% cycle 'add row' : '<div class="row">', nil, nil, nil %
<div class="column">
<!-- liquid tags here -->
</div>
% cycle 'end row' : nil, nil, nil, '</div>' %
% endfor %
% cycle 'end row' : nil, '</div>', '</div>', '</div>' %
</div>
三栏:
<div class="container">
% for post in site.posts %
% cycle 'add row' : '<div class="row">', nil, nil %
<div class="column">
<!-- liquid tags here -->
</div>
% cycle 'end row' : nil, nil, '</div>' %
% endfor %
% cycle 'end row' : nil, '</div>', '</div>' %
</div>
两列:
<div class="container">
% for post in site.posts %
% cycle 'add row' : '<div class="row">', nil %
<div class="column">
<!-- liquid tags here -->
</div>
% cycle 'end row' : nil, '</div>' %
% endfor %
% cycle 'end row' : nil, '</div>' %
</div>
【讨论】:
【参考方案7】:IIRC Liquid 不会阻止模运算,只会阻止 %
字符。您可以在不使用 %
运算符的情况下执行取模。例如,14.modulo(3) => 2
而不是 14 % 3
。
【讨论】:
确实有道理,因为所有其他算术函数都是这样抽象出来的,但不幸的是,modulo
或 modulus
都不起作用……
是的。刚刚检查了源代码。可悲的是,没有modulo
。我可能不得不分叉并添加它或其他东西。我目前的解决方案是一团糟:unless total == 3 or total == 6 or total == 9 or total == 12 or total == 15…
x.modulo(y)
只是x.divmod(y)[1]
的别名。如果允许divmod
,您可以使用该表单。或者,您可以随时滚动您自己的模函数:x - (x / y)
(使用您需要的任何抽象版本的算术运算符)。以上是关于Ruby 的 Liquid 模板引擎中的模数(或缺少模数)的主要内容,如果未能解决你的问题,请参考以下文章