用Jekyll和Liquid分类导航菜单
我正在用Jekyll / Liquid构build一个静态网站(没有博客)。 我希望它有一个自动生成的导航菜单,列出所有现有的页面,并突出显示当前页面。 这些项目应该以特定顺序添加到菜单中。 因此,我在页面的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>
这创build了所有现有页面的链接,但是它们是未sorting的, sort
filter似乎被忽略。 显然,我做错了什么,但是我弄不清楚是什么。
由于Jekyll 2.2.0,您可以通过任何对象属性对对象数组进行sorting。 你现在可以做:
{% 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解决scheme相比,节省了大量的构build时间。
编辑 :你必须指定你的sorting属性为一个整数weight: 10
而不是一个stringweight: "10"
。
以stringforms分配sorting属性将以“1,10,11,2,20 ……”这样的stringsorting结束。
你唯一的select似乎是使用双循环。
<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 %}
。
下面的解决scheme在Github上工作(不需要插件):
{% assign sorted_pages = site.pages | sort:"name" %} {% for node in sorted_pages %} <li><a href="{{node.url}}">{{node.title}}</a></li> {% endfor %}
上面的代码片段按文件名sorting页面(页面对象上的name
属性是从文件名派生的)。 我重新命名文件以匹配我所需的顺序: 00-index.md
, 01-about.md
– 然后! 页面已订购。
一个问题是,这些数字前缀最终在URL中,这对于大多数页面来说看起来很尴尬,并且在00-index.html中是一个真正的问题。 Permalilnks救援:
--- layout: default title: News permalink: "index.html" ---
PS我想变得聪明,只为sorting添加自定义属性。 不幸的是自定义属性不能作为Page类的方法访问,因此不能用于sorting:
{% assign sorted_pages = site.pages | sort:"weight" %} #bummer
我已经写了一个简单的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
而不是sort_by:property
参数来按给定的属性进行sorting。 你也可以添加reversed
就像原来for
。 - 不要忘记使用不同的结束标签
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>
最简单的解决scheme就是在页面的文件名前添加一个像这样的索引:
00-home.html 01-services.html 02-page3.html
页面按文件名sorting。 但是,现在你会有丑陋的url。
在你的yaml前端部分,你可以通过设置permalinkvariables来覆盖生成的url。
例如:
--- layout: default permalink: index.html ---
简易解决scheme
先分配一个有序的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 %}
这工作在我的navbar _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>
我用一个发生器解决了这个问题。 生成器迭代页面,获取导航数据,对其进行sorting并将其推回到站点configuration。 从那里液体可以检索数据并显示它。 它也照顾隐藏和显示项目。
考虑这个页面片段:
--- navigation: title: Page name weight: 100 show: true --- content.
导航与这个液体片段呈现:
{% 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还是比较陌生的,所以如果有人能够改进的话,那将是非常棒的。
我可以把下面的代码与Jekyll / Liquid匹配到您的要求与类别:
- 创build所有现有页面的链接,
- 按重量分类(按照类别进行分类),
- 突出显示当前页面。
在他们之上它显示也岗位的数字。 全部完成没有任何插件。
<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页面上的行动。 您可以点击post突出显示导航,也可以点击给定的链接,将您带到分配权重的源页面。
如果你想按重量和标签进行分类,并将数量限制为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 %}
上面的@kikito解决scheme也为我工作。 我只是添加了几行删除页面没有重量从导航和摆脱空白:
<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>