带有Jekyll和Liquid的分类导航菜单

时间:2012-01-29 12:11:45

标签: jekyll liquid

我正在使用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过滤器似乎会被忽略。显然,我做错了什么,但我无法弄清楚是什么。

10 个答案:

答案 0 :(得分:74)

从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,...”

答案 1 :(得分:36)

您唯一的选择似乎是使用双循环。

<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>

丑陋,它应该工作。如果您还有没有重量的页面,则必须在当前内部页面之前/之后添加一个额外的内部循环{/ 1}}。

答案 2 :(得分:29)

以下解决方案适用于Github(不需要插件):

{% assign sorted_pages = site.pages | sort:"name" %}
{% for node in sorted_pages %}
  <li><a href="{{node.url}}">{{node.title}}</a></li>
{% endfor %}

上面的代码段按文件名对页面进行排序(页面对象上的name属性是从文件名派生的)。我重命名了文件以匹配我想要的订单:00-index.md01-about.md - 和presto!订购页面。

一个问题是,这些数字前缀最终会出现在URL中,对于大多数页面来说这看起来很尴尬,并且在00-index.html中是一个真正的问题。救援人员:

---
layout: default
title: News
permalink: "index.html"
---

P.S。我想要聪明并添加自定义属性只是为了排序。遗憾的是,自定义属性无法作为Page类上的方法访问,因此无法用于排序:

{% assign sorted_pages = site.pages | sort:"weight" %} #bummer

答案 3 :(得分:15)

我写了一个简单的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代替带有for参数的sort_by:property来按给定属性进行排序。您也可以像原始reversed一样添加for
  3. 不要忘记使用不同的结束标记endsorted_for
  4. 在您的情况下,用法如下所示:

    <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>
    

答案 4 :(得分:10)

最简单的解决方案是在页面的文件名前添加如下索引:

00-home.html做为 01-services.html 02-page3.html

页面按文件名排序。但是,现在你会有丑陋的网址。

在您的yaml前端部分中,您可以通过设置永久链接变量来覆盖生成的网址。

例如:

---
layout: default
permalink: index.html
---

答案 5 :(得分:10)

简易解决方案:

首先分配一个排序数组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>

答案 6 :(得分:5)

我用发电机解决了这个问题。生成器迭代页面,获取导航数据,对其进行排序并将其推回到站点配置。从那里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都很陌生,所以如果有人能改进这一点,那将会很棒。

答案 7 :(得分:1)

我可以通过类别获得以下代码: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 上的操作。您可以单击帖子以突出显示导航,也可以单击指定链接以转到指定权重的源页面。

答案 8 :(得分:0)

如果您尝试按重量和标记进行排序并将数量限制为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 %} 

答案 9 :(得分:-1)

@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>