用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的, sortfilter似乎被忽略。 显然,我做错了什么,但是我弄不清楚是什么。

由于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.md01-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插件来解决这个问题:

  1. sorted_for.rbhttps://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) 
  2. 使用标记sorted_for而不是sort_by:property参数来按给定的属性进行sorting。 你也可以添加reversed就像原来for
  3. 不要忘记使用不同的结束标签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>