带有 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.md01-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 而不是forsort_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

Jekyll 教程——模板语言 Liquid

Jekyll/Liquid - 如何将大块文本添加到 YAML 前端?

在 Jekyll/Liquid 和 pygments 的 html 问题中突出显示

Jekyll/Liquid 模板:如何按年份对博客文章进行分组?

Windows Liquid 上的 Jekyll 异常:无法获取标题