Сортированное меню навигации с Jekyll и Liquid

Я создаю статический сайт (без блога) с помощью Jekyll /Liquid. Я хочу, чтобы в нем было автоматически сгенерированное меню навигации, в котором перечислены все существующие страницы и выделена текущая страница. Элементы должны быть добавлены в меню в определенном порядке. Поэтому я определяю свойство weight в YAML страниц:

---
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, похоже, игнорируется. Очевидно, что я делаю что-то не так, но я не могу понять, что.

68 голосов | спросил flyx 29 Jpm1000000pmSun, 29 Jan 2012 16:11:45 +040012 2012, 16:11:45

9 ответов


0

Начиная с 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, ..."

ответил David Jacquel 26 PM000000110000004431 2014, 23:41:44
0

Похоже, ваш единственный вариант - использовать двойной цикл.

<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 %} до /после текущего внутреннего.

ответил kikito 3 FebruaryEurope/MoscowbFri, 03 Feb 2012 13:21:38 +0400000000pmFri, 03 Feb 2012 13:21:38 +040012 2012, 13:21:38
0

Ниже решение работает на Github (не требует плагина):

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

Вышеупомянутый фрагмент сортирует страницы по имени файла (атрибут name объекта Page получен из имени файла). Я переименовал файлы в соответствии с желаемым порядком: 00-index.md, 01-about.md - и просто! Страницы упорядочены.

Одна хитрость заключается в том, что эти префиксы номеров заканчиваются в URL, что выглядит неудобно для большинства страниц и является реальной проблемой в 00-index.html. Permalilnks на помощь:

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

P.S. Я хотел быть умным и добавлять пользовательские атрибуты только для сортировки. К сожалению, пользовательские атрибуты не доступны как методы класса Page и поэтому не могут использоваться для сортировки:

{% assign sorted_pages = site.pages | sort:"weight" %} #bummer
ответил Wojtek Kruszewski 18 Maypm13 2013, 18:46:50
0

Я написал простой плагин Jekyll для решения этой проблемы:

  1. Скопируйте sorted_for.rb из https: //gist .github.com /3765912 в подкаталог _plugins вашего проекта Jekyll:

    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.

В вашем случае использование выглядит следующим образом:

<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>
ответил Jan Dupal 22 ndEurope/Moscowp30Europe/Moscow09bEurope/MoscowSat, 22 Sep 2012 16:01:32 +0400 2012, 16:01:32
0

Самым простым решением было бы добавить к имени файла ваших страниц такой индекс:

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

Страницы упорядочены по имени файла. Однако теперь у вас будут ужасные ссылки.

В ваших разделах, посвященных теме yaml, вы можете переопределить сгенерированный URL, установив переменную permalink.

Например:

---
layout: default
permalink: index.html
---
ответил Mark Meeus 20 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 20 Sep 2012 12:03:57 +0400 2012, 12:03:57
0

Я решил это с помощью генератора. Генератор перебирает страницы, получает навигационные данные, сортирует их и возвращает обратно в конфигурацию сайта. Оттуда 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

Я потратил довольно много времени на то, чтобы понять это, так как я довольно новичок в Джекилле и Руби, поэтому было бы здорово, если бы кто-нибудь смог улучшить это.

ответил kevin 8 PM00000070000000131 2012, 19:28:01
0

Я могу получить приведенный ниже код, который работает с 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>

Проверьте это на нашем сетевой странице . Вы можете щелкнуть сообщение, чтобы выделить навигацию, а также данную ссылку, чтобы перенести вас на исходную страницу, где указан их вес.

ответил Chetabahana 5 J0000006Europe/Moscow 2016, 15:57:31
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 %} 
ответил Tom Johnson 4 FebruaryEurope/MoscowbWed, 04 Feb 2015 10:47:52 +0300000000amWed, 04 Feb 2015 10:47:52 +030015 2015, 10:47:52
0

Приведенное выше решение @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>
ответил jupiteror 7 PMpMon, 07 Apr 2014 17:31:38 +040031Monday 2014, 17:31:38

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132