带有 Jekyll 和 Liquid 的排序导航菜单
Posted
技术标签:
【中文标题】带有 Jekyll 和 Liquid 的排序导航菜单【英文标题】:Sorted navigation menu with Jekyll and Liquid 【发布时间】:2012-02-21 14:37:24 【问题描述】:我正在使用 Jekyll/Liquid 构建一个静态站点(没有博客)。我希望它有一个自动生成的导航菜单,列出所有现有页面并突出显示当前页面。这些项目应按特定顺序添加到菜单中。因此,我在页面的 YAML 中定义了一个weight
属性:
---
layout : default
title : Some title
weight : 5
---
导航菜单的构造如下:
<ul>
% for p in site.pages | sort:weight %
<li>
<a % if p.url == page.url %class="active"% endif % href=" p.url ">
p.title
</a>
</li>
% endfor %
</ul>
这会创建指向所有现有页面的链接,但它们未排序,sort
过滤器似乎被忽略了。显然,我做错了什么,但我不知道是什么。
【问题讨论】:
我刚刚发现:sort
做了 的事情。如果网站没有提供weight
,则最后写入。但是如果确实提供了一个,仍然不是按照它排序,而是按照文件名排序。
我相信排序过滤器可能只适用于输出标记(包装在 中的东西,而不是 % %)。因此,它可能无法用作 for 循环上的过滤器。我的评论基于此页面:github.com/Shopify/liquid/wiki/Liquid-for-Designers,它说过滤器用于输出标记。
【参考方案1】:
从 Jekyll 2.2.0 开始,您可以按任何对象属性对对象数组进行排序。你现在可以这样做了:
% assign pages = site.pages | sort:"weight" %
<ul>
% for p in pages %
<li>
<a % if p.url == page.url %class="active"% endif % href=" p.url ">
p.title
</a>
</li>
% endfor %
</ul>
与@kikito 解决方案相比,节省了大量构建时间。
编辑:
您必须将排序属性指定为整数 weight: 10
,而不是字符串 weight: "10"
。
将排序属性指定为字符串将以字符串排序结束,例如“1, 10, 11, 2, 20, ...”
【讨论】:
对我不起作用(Jekyll 2.4.0)。如上所述,我在页面中定义了 weight 属性,但排序似乎忽略了它。 @eyetea 你是对的。我们需要先做一个作业。我编辑了我的代码,它适用于 Jekyll 2.4.0。 ;-) 感谢您的帮助。我还编辑了代码并删除了第二个排序过滤器,因为它看起来不再需要了。 你是对的。我自己编辑了它,因为您建议的编辑被 3 个用户拒绝了??? 奇怪,我刚刚删除了“| sort: weight”……为什么会被拒绝?总之,问题解决了。【参考方案2】:您唯一的选择似乎是使用双循环。
<ul>
% for weight in (1..10) %
% for p in site.pages %
% if p.weight == weight %
<li>
<a % if p.url == page.url %class="active"% endif % href=" p.url ">
p.title
</a>
</li>
% endif %
% endfor %
% endfor %
</ul>
虽然丑陋,但它应该可以工作。如果您还有没有权重的页面,则必须在当前内部循环之前/之后添加一个额外的内部循环,只需执行 % unless p.weight %
。
【讨论】:
哈哈。我想如果这是一个问题,你可以通过将所有内容压缩成一行代码来减少它。不幸的是,liquid 没有%-
%
前缀来折叠像 erb 这样的空行。
只是一个补充:将 (1..10) 替换为 (1..site.pages.size) 使此循环尽可能短,并且无论您拥有多少页都可以正常工作。感谢一个愚蠢但非常聪明的黑客:)
@MarkusAmaltheaMagnuson 此代码上的(1..10)
表示可能的权重。可以将其替换为(1..MAX_WEIGHT)
以使其更加清晰(并在其他地方定义 MAX_WEIGHT,例如在常量文件中)。
这对我有用,除了“活动”类需要在 而不是
这是 Jekyll/static-generation 最好的事情之一——尽管它可能很“丑陋”,但它只运行一次,不会影响用户体验或服务器负载。 不错的解决方案!【参考方案3】:
以下解决方案适用于 Github(不需要插件):
% assign sorted_pages = site.pages | sort:"name" %
% for node in sorted_pages %
<li><a href="node.url">node.title</a></li>
% endfor %
sn-p 以上按文件名对页面进行排序(Page 对象上的name
属性源自文件名)。我重命名了文件以匹配我想要的顺序:00-index.md
、01-about.md
- 并且很快!页面是有序的。
一个问题是这些数字前缀最终出现在 URL 中,这对于大多数页面来说看起来很尴尬,并且在 00-index.html 中是一个真正的问题。永久链接到救援:
---
layout: default
title: News
permalink: "index.html"
---
附:我想聪明点,添加自定义属性只是为了排序。不幸的是,自定义属性不能作为 Page 类的方法访问,因此不能用于排序:
% assign sorted_pages = site.pages | sort:"weight" % #bummer
【讨论】:
你好先生应该获得奖章。我正要求助于在本地生成我的网站并将静态 HTML 推送到 GitHub 以便能够使用插件来执行此操作。 这适用于按完整文件路径排序吗?即% assign sorted_pages = site.pages | sort:"path" %
和00-directory/00-file.md
将在01-anotherDir/00-anotherFile.md
之前出现
它确实有效!非常感谢!我已经为此奋斗了好几天。
嗨 @Wojtek sort:"weight"
对我有用,仅供参考。顺便感谢您提供的出色解决方案。
按重量排序确实有效! See answer below 也许 Jekyll 改变了。【参考方案4】:
我写了一个简单的 Jekyll 插件来解决这个问题:
将 sorted_for.rb
从 https://gist.github.com/3765912 复制到 Jekyll 项目的 _plugins
子目录:
module Jekyll
class SortedForTag < Liquid::For
def render(context)
sorted_collection = context[@collection_name].dup
sorted_collection.sort_by! |i| i.to_liquid[@attributes['sort_by']]
sorted_collection_name = "#@collection_name_sorted".sub('.', '_')
context[sorted_collection_name] = sorted_collection
@collection_name = sorted_collection_name
super
end
def end_tag
'endsorted_for'
end
end
end
Liquid::Template.register_tag('sorted_for', Jekyll::SortedForTag)
使用标签sorted_for
而不是for
和sort_by:property
参数按给定属性排序。你也可以像原来的for
一样添加reversed
。
别忘了使用不同的结束标签endsorted_for
。
在您的情况下,用法如下所示:
<ul>
% sorted_for p in site.pages sort_by:weight %
<li>
<a % if p.url == page.url %class="active"% endif % href=" p.url ">
p.title
</a>
</li>
% endsorted_for %
</ul>
【讨论】:
可惜不能在 GitHub 页面上使用自定义插件... :-\ 很好,谢谢分享。只是一点点补充:如果不是所有项目都具有指定的属性,您可以更改sort_by!
调用以忽略这些项目:sorted_collection.sort_by! |i| i.to_liquid[@attributes['sort_by']] || 0
(如果您想要它,请将 0 替换为无穷大)。跨度>
【参考方案5】:
最简单的解决方案是在页面的文件名前加上这样的索引:
00-home.html 01-services.html 02-page3.html
页面按文件名排序。但是,现在你的网址会很丑。
在您的 yaml 前端部分中,您可以通过设置永久链接变量来覆盖生成的 url。
例如:
---
layout: default
permalink: index.html
---
【讨论】:
不错的一个!仍然是一个 hack,但比其他答案简单得多。 如果您将网站推送到 github 页面,请注意这一点。由于某种原因,订购会被搞砸。另见:github.com/plusjade/jekyll-bootstrap/issues/…【参考方案6】:简单的解决方案:
首先分配一个site.pages
的排序数组,然后在该数组上运行 for 循环。
您的代码将如下所示:
% assign links = site.pages | sort: 'weight' %
% for p in links %
<li>
<a % if p.url == page.url %class="active"% endif % href=" p.url ">
p.title
</a>
</li>
% endfor %
这适用于我的导航栏_include
,这很简单:
<section id="navbar">
<nav>
% assign tabs = site.pages | sort: 'weight' %
% for p in tabs %
<span class="navitem"><a href=" p.url "> p.title </a></span>
% endfor %
</nav>
</section>
【讨论】:
这突然开始在_post页面上抛出错误:Liquid Exception: comparison of Hash with Hash failed in _posts/...
这是最干净的解决方案;只是一个小错误——排序键应该作为字符串给出,即排序:'重量'。更新了示例代码。
上述问题已被提及并解决here。不过,运行 GitHub 页面的版本可能需要一段时间才能更新。【参考方案7】:
我已经使用生成器解决了这个问题。生成器遍历页面,获取导航数据,对其进行排序并将其推送回站点配置。 Liquid 可以从那里检索数据并显示它。它还负责隐藏和显示项目。
考虑这个页面片段:
---
navigation:
title: Page name
weight: 100
show: true
---
content.
导航是使用这个 Liquid 片段呈现的:
% for p in site.navigation %
<li>
<a % if p.url == page.url %class="active"% endif % href=" p.url "> p.navigation.title </a>
</li>
% endfor %
将以下代码放入 _plugins 文件夹中的文件中:
module Jekyll
class SiteNavigation < Jekyll::Generator
safe true
priority :lowest
def generate(site)
# First remove all invisible items (default: nil = show in nav)
sorted = []
site.pages.each do |page|
sorted << page if page.data["navigation"]["show"] != false
end
# Then sort em according to weight
sorted = sorted.sort |a,b| a.data["navigation"]["weight"] <=> b.data["navigation"]["weight"]
# Debug info.
puts "Sorted resulting navigation: (use site.config['sorted_navigation']) "
sorted.each do |p|
puts p.inspect
end
# Access this in Liquid using: site.navigation
site.config["navigation"] = sorted
end
end
end
由于我对 Jekyll 和 Ruby 还很陌生,所以我花了很长时间才弄清楚这一点,所以如果有人可以改进这一点,那就太好了。
【讨论】:
【参考方案8】:我可以让下面的代码与 Jekyll/Liquid 一起使用,以满足您对类别的要求:
创建指向所有现有页面的链接, 按重量排序(也适用于按类别排序), 突出显示当前页面。
在它们之上,它还显示了帖子的数量。一切都是在没有任何插件的情况下完成的。
<ul class="topics">
% capture tags %
% for tag in site.categories %
tag[0]
% endfor %
% endcapture %
% assign sortedtags = tags | split:' ' | sort %
% for tag in sortedtags %
<li class="topic-header"><b> tag ( site.categories[tag] | size topics)</b>
<ul class='subnavlist'>
% assign posts = site.categories[tag] | sort:"weight" %
% for post in posts %
<li class='recipe % if post.url == page.url %active% endif %'>
<a href="/ site.github.project_title post.url "> post.title </a>
</li>
% endfor %
</ul>
</li>
% endfor %
</ul>
在我们的 networking page 上查看操作。您可以单击帖子以突出显示导航,也可以单击给定的链接将您带到为其分配权重的源页面。
【讨论】:
【参考方案9】:如果您尝试按重量和标签排序并将数量限制为 10,请执行以下代码:
% assign counter = '0' %
% assign pages = site.pages | sort: "weight" %
% for page in pages %
% for tag in page.tags %
% if tag == "Getting Started" and counter < '9' %
% capture counter % counter | plus:'1' % endcapture %
<li><a href=" page.permalink | prepend: site.baseurl ">page.title</a></li>
% endif %
% endfor %
% endfor %
【讨论】:
【参考方案10】:@kikito 的上述解决方案也对我有用。我只是添加了几行来从导航中删除没有重量的页面并摆脱空白:
<nav>
<ul>
% for weight in (1..5) %
% unless p.weight %
% for p in site.pages %
% if p.weight == weight %
% if p.url == page.url %
<li> p.title </li>
% else %
<li><a href=" p.url " title=" p.title "> p.title </a></li>
% endif %
% endif %
% endfor %
% endunless %
% endfor %
</ul>
</nav>
【讨论】:
@WingLeong 我没有做任何测试,但这对我有用。以上是关于带有 Jekyll 和 Liquid 的排序导航菜单的主要内容,如果未能解决你的问题,请参考以下文章
Jekyll/Liquid - 如何将大块文本添加到 YAML 前端?
在 Jekyll/Liquid 和 pygments 的 html 问题中突出显示