導覽
如果你的 Jekyll 網站有很多頁面,你可能會想要為這些頁面建立導覽。你可以透過程式化取得頁面清單來建立網站導覽,而不需要硬編碼導覽連結。
雖然其他 Jekyll 文件中已有關於 與資料檔案互動 的資訊,但本教學會深入探討如何為你的網站建立更強大的導覽功能。
有兩種主要方式可以在 Jekyll 網站上取得頁面
- 取得 YAML 資料來源中列出的頁面。將頁面資料儲存在
_data
資料夾中的 YAML(或 JSON 或 CSV)檔案中,迴圈 YAML 屬性,並將值插入你的佈景主題。 - 透過迴圈頁面前言資料來取得頁面。查看頁面的前言資料以找出特定屬性,傳回這些頁面,並將頁面的前言資料值插入你的佈景主題。
以下範例從基本的導覽情境開始,並加入更精密的元素,以示範傳回頁面的不同方式。在每個情境中,您會看到 3 個元素
- YAML
- Liquid
- 結果
_data
目錄中的 YAML 檔案稱為 samplelist.yml
。
情境如下
- 情境 1:基本清單
- 情境 2:已排序清單
- 情境 3:二層導覽清單
- 情境 4:三層導覽清單
- 情境 5:使用頁面變數來選取 YAML 清單
- 情境 6:套用目前頁面的 active 類別
- 情境 7:有條件地包含項目
- 情境 8:根據前置屬性擷取項目
- 情境 9:使用遞迴進行巢狀樹狀導覽
情境 1:基本清單
您想要傳回基本頁面清單。
YAML
docs_list_title: ACME Documentation
docs:
- title: Introduction
url: introduction.html
- title: Configuration
url: configuration.html
- title: Deployment
url: deployment.html
Liquid
<h2>{{ site.data.samplelist.docs_list_title }}</h2>
<ul>
{% for item in site.data.samplelist.docs %}
<li><a href="{{ item.url }}">{{ item.title }}</a></li>
{% endfor %}
</ul>
結果
對於這些虛構範例中的結果,#
手動替換為實際連結值(以避免 404 錯誤)。
當您使用 for
迴圈時,您可以選擇要如何參照您正在迴圈的項目。您選擇的變數(在本例中為 item
)會變成您存取清單中每個項目屬性的方式。點狀符號用於取得項目的屬性(例如,item.url
)。
YAML 內容有兩種主要格式與此相關
- 對應
- 清單
docs_list_title: ACME Documentation
是對應。您可以使用 site.data.samplelist.docs_list_title
存取值。
文件:
是一個清單。清單中每個項目都以連字號開頭。與對應不同,您通常不會像對應那樣直接存取清單屬性。如果您想要存取清單中的特定項目,您必須找出您在清單中的位置,並遵循典型的陣列表示法。例如,site.data.samplelist.docs[0]
會存取清單中的第一個項目。不過,這很少見。
對於清單,您通常會使用for
迴圈來循環清單中的項目,並對每個項目執行某些動作。對於導覽選單,您通常會根據 HTML 主題中使用的導覽結構,將每個清單項目插入li
標籤中。
每個連字號 (-
) 表示清單中的另一個項目。此範例僅在每個清單項目中具有兩個屬性:標題
和網址
。您可以為每個項目包含任意數量的屬性。清單中每個位置的屬性順序並不重要。
情境 2:已排序清單
假設您想要依據標題
對清單進行排序。為此,請將對文件
集合的參照轉換為變數,然後將 Liquid 的排序
篩選器套用至變數
Liquid
{% assign doclist = site.data.samplelist.docs | sort: 'title' %}
<ol>
{% for item in doclist %}
<li><a href="{{ item.url }}">{{ item.title }}</a></li>
{% endfor %}
</ol>
結果
項目現在以字母順序顯示。sort
屬性在 Liquid 篩選器中套用至 title
,這是清單中的實際屬性。如果 title
不是屬性,我們需要依據其他屬性排序。
請參閱 Liquid 陣列篩選器 以取得更多篩選器選項。請注意,您無法僅使用此語法
{% for item in site.data.samplelist.docs | sort: "title" %}{% endfor %}
您必須先使用 assign
或 capture
標籤將 site.data.samplelist.docs
轉換為變數。
情境 3:二層導覽清單
假設您想要一個更強大的清單,其中包含標題和子項目的多個區段。為執行此操作,請為每個清單項目新增一個額外層級來儲存此資訊
YAML
toc:
- title: Group 1
subfolderitems:
- page: Thing 1
url: /thing1.html
- page: Thing 2
url: /thing2.html
- page: Thing 3
url: /thing3.html
- title: Group 2
subfolderitems:
- page: Piece 1
url: /piece1.html
- page: Piece 2
url: /piece2.html
- page: Piece 3
url: /piece3.html
- title: Group 3
subfolderitems:
- page: Widget 1
url: /widget1.html
- page: Widget 2
url: /widget2.html
- page: Widget 3
url: /widget3.html
Liquid
{% for item in site.data.samplelist.toc %}
<h3>{{ item.title }}</h3>
<ul>
{% for entry in item.subfolderitems %}
<li><a href="{{ entry.url }}">{{ entry.page }}</a></li>
{% endfor %}
</ul>
{% endfor %}
結果
在此範例中,Group 1
是第一個清單項目。在該清單項目中,其子頁面包含為屬性,而該屬性本身包含一個清單 (subfolderitems
)。
Liquid 程式碼會透過 for item in site.data.samplelist.toc
查看第一個層級,然後透過 for entry in item.subfolderitems
查看第二個層級屬性。正如 item
是我們在其中執行迴圈的項目的任意名稱,entry
也是如此。
情境 4:三層導覽清單
根據前一區段,讓我們為清單新增一個更深的層級 (subsubfolderitems
)。格式會變得更複雜,但原則相同。
YAML
toc2:
- title: Group 1
subfolderitems:
- page: Thing 1
url: /thing1.html
- page: Thing 2
url: /thing2.html
subsubfolderitems:
- page: Subthing 1
url: /subthing1.html
- page: Subthing 2
url: /subthing2.html
- page: Thing 3
url: /thing3.html
- title: Group 2
subfolderitems:
- page: Piece 1
url: /piece1.html
- page: Piece 2
url: /piece2.html
- page: Piece 3
url: /piece3.html
subsubfolderitems:
- page: Subpiece 1
url: /subpiece1.html
- page: Subpiece2
url: /subpiece2.html
- title: Group 3
subfolderitems:
- page: Widget 1
url: /widget1.html
subsubfolderitems:
- page: Subwidget 1
url: /subwidget1.html
- page: Subwidget 2
url: /subwidget2.html
- page: Widget 2
url: /widget2.html
- page: Widget 3
url: /widget3.html
Liquid
<div>
{% if site.data.samplelist.toc2[0] %}
{% for item in site.data.samplelist.toc2 %}
<h3>{{ item.title }}</h3>
{% if item.subfolderitems[0] %}
<ul>
{% for entry in item.subfolderitems %}
<li><a href="{{ entry.url }}">{{ entry.page }}</a>
{% if entry.subsubfolderitems[0] %}
<ul>
{% for subentry in entry.subsubfolderitems %}
<li><a href="{{ subentry.url }}">{{ subentry.page }}</a></li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
{% endfor %}
{% endif %}
</div>
結果
在此範例中,if site.data.samplelist.toc2[0]
用於確保 YAML 層級實際包含項目。如果 [0]
位置沒有任何項目,我們可以跳過在這個層級中尋找。
專業提示:對齊 for
迴圈和 if
陳述式
為保持程式碼清晰,請對齊開始和結束的 Liquid 標籤,例如 for
迴圈和 if
陳述式。這樣您就知道何時已關閉開啟的標籤。如果程式碼將出現在 Markdown 頁面中,請保持開啟和關閉 HTML 標籤與左邊緣齊平,這樣 Markdown 篩選器才不會將內容視為程式碼範例。必要時,您可以將整個程式碼範例包在 div
標籤中,以確保程式碼具有標記程式碼起訖的 HTML 標籤。
情境 5:使用頁面變數來選取 YAML 清單
假設您的側邊欄會根據不同的文件集而有所不同。您的網站上可能有 3 種不同的產品,因此您想要 3 個不同的側邊欄,每個側邊欄都針對該產品而獨特。
您可以將側邊欄清單的名稱儲存在頁面開頭資訊中,然後將該值動態傳遞到清單中。
頁面開頭資訊
---
title: My page
sidebar: toc
---
Liquid
<ul>
{% for item in site.data.samplelist[page.sidebar] %}
<li><a href="{{ item.url }}">{{ item.title }}</a></li>
{% endfor %}
</ul>
結果
在此範例中,我們要將頁面開頭資訊中的值傳遞到包含變數的 for
迴圈中。當指定的變數不是字串而是資料參考時,您必須使用方括號(而不是大括號)來參照開頭資訊的值。
有關更多資訊,請參閱 Liquid 文件中的 運算式和變數。在無法使用點號符號的地方使用括號。您也可以在這個 Stack Overflow 回答 中閱讀更多詳細資訊。
情境 6:套用目前頁面的 active 類別
除了將 YAML 資料檔中的項目插入清單中之外,您通常還希望在使用者檢視該頁面時,將目前的連結反白顯示。您可以為與目前頁面 URL 相符的項目插入 active
類別來達成此目的。
CSS
.result li.active a {
color: lightgray;
cursor: default;
}
Liquid
{% for item in site.data.samplelist.docs %}
<li class="{% if item.url == page.url %}active{% endif %}">
<a href="{{ item.url }}">{{ item.title }}</a>
</li>
{% endfor %}
結果
在此情況下,假設 Deployment
是目前的頁面。
為確保 item.url
(儲存在 YAML 檔中)與 page.url
相符,將 {{ page.url }}
印到頁面上會很有幫助。
情境 7:有條件地包含項目
您可能希望有條件地將項目包含在清單中。例如,您有多個網站輸出,而且只希望將側邊欄項目包含在某些輸出中。您可以在每個清單項目中新增屬性,然後使用這些屬性有條件地包含內容。
YAML
docs2_list_title: ACME Documentation
docs2:
- title: Introduction
url: introduction.html
version: 1
- title: Configuration
url: configuration.html
version: 1
- title: Deployment
url: deployment.html
version: 2
Liquid
<ul>
{% for item in site.data.samplelist.docs2 %}
{% if item.version == 1 %}
<li><a href="{{ item.url }}">{{ item.title }}</a></li>
{% endif %}
{% endfor %}
</ul>
結果
會排除 Deployment
頁面,因為它的 version
是 2
。
情境 8:根據前置屬性擷取項目
如果您不希望將您的導覽項目儲存在 _data
資料夾中的 YAML 檔中,您可以使用 for
迴圈來查看每個頁面或彙整的開頭資料,並根據開頭資料中的屬性取得內容。
在此情境中,假設我們有一個名為 _docs
的集合。集合通常比頁面好,因為它們允許你縮小要迴圈處理的清單。(盡量避免在大量項目中迴圈處理的情境,因為這會增加你的建置時間。 集合 能幫助你縮小範圍。)
在我們的範例中,docs
集合中有 6 個文件:範例 1、範例 2、主題 1、主題 2、小工具 1 和小工具 2。
集合中的每個文件在 front matter 中至少包含 3 個屬性
標題
類別
順序
為了簡潔起見,每個頁面的 front matter 如下(在此合併)
---
Title: Sample 1
category: getting-started
order: 1
---
---
Title: Sample 2
category: getting-started
order: 2
---
---
Title: Topic 1
category: configuration
order: 1
---
---
Title: Topic 2
category: configuration
order: 2
---
---
Title: Widget 1
category: deployment
order: 1
---
---
Title: Widget 2
category: deployment
order: 2
---
請注意,即使 類別
用於文件 front matter 中,類別
並不是內建變數,就像用於文章一樣。換句話說,你無法使用 site.docs.category
直接查看 類別
內部。
如果你只想取得特定類別中集合中的所有文件,你可以使用 for
迴圈和 if
條件來檢查特定類別
<h3>Getting Started</h3>
<ul>
{% for doc in site.docs %}
{% if doc.category == "getting-started" %}
<li><a href="{{ doc.url }}">{{ doc.title }}</a></li>
{% endif %}
{% endfor %}
</ul>
結果如下
如果你正在建立知識庫,並且每個類別中有數十個主題,每個類別都顯示在其自己的頁面上,這可能會很有用。
但假設你想要按類別對項目進行排序,並將它們分組在類別名稱下,而不對類別名稱進行硬編碼。為達成此目的,你可以使用兩個篩選器
group_by
sort
以下是取得頁面清單並依其對應類別標題分組的程式碼
Liquid
{% assign mydocs = site.docs | group_by: 'category' %}
{% for cat in mydocs %}
<h2>{{ cat.name | capitalize }}</h2>
<ul>
{% assign items = cat.items | sort: 'order' %}
{% for item in items %}
<li><a href="{{ item.url }}">{{ item.title }}</a></li>
{% endfor %}
</ul>
{% endfor %}
結果
讓我們逐步了解程式碼。首先,我們將變數 (mydocs
) 指定給集合內容 (site.docs
)。
group_by
篩選器依 類別
將集合內容分組。更具體地說,group_by
篩選器會將 mydocs
轉換成具有 名稱
、項目
和 大小
屬性的陣列,如下所示
[
{"name": "getting-started", "items": [Sample 1, Sample 2],"size": 2},
{"name": "configuration", "items": [Topic 1, Topic 2], "size": 2},
{"name": "deployment", "items": [Widget 1, Widget 2], "size": 2}
]
使用 for cat in mydocs
,我們會查看 mydocs
陣列中的每個項目,並列印類別 名稱
。
取得類別名稱後,我們將變數 項目
指定給文件,並使用 排序
篩選器依其 順序
屬性排列文件。點號表示法 cat.items
用於存取 項目
陣列中的內容。 排序
篩選器會依據數字以遞增順序排列項目。
for item in items
迴圈會檢視每個 item
,並取得 title
和 url
以形成清單項目連結。
有關 group_by
篩選器的更多詳細資料,請參閱 Jekyll 的範本文件,以及 這個 Siteleaf 教學。有關 sort
篩選器的更多詳細資料,請參閱 Liquid 文件中的 sort。
不論您是在文件的 front matter 中使用屬性來擷取您的頁面,或使用 YAML 資料檔案,在兩種情況下您都可以為您的網站編寫更強固的導覽。
情境 9:使用遞迴進行巢狀樹狀導覽
假設您想要一個任何深度的巢狀樹狀導覽。我們可以透過遞迴地迴圈我們的導覽連結樹狀結構來達成此目的。
YAML
nav:
- title: Deployment
url: deployment.html
subnav:
- title: Heroku
url: heroku.html
subnav:
- title: Jekyll on Heroku
url: jekyll-on-heroku.html
- title: Help
url: help.html
Liquid
首先,我們將建立一個包含檔,我們可以使用它來呈現導覽樹狀結構。這個檔案將會是 _includes/nav.html
<ul>
{% for item in include.nav %}
<li><a href="{{ item.url }}">{{ item.title }}</a>
{% if item.subnav %}
{% include nav.html nav=item.subnav %}
{% endif %}
</li>
{% endfor %}
</ul>
要在您的版面配置或頁面中呈現這個,您只要包含範本並傳入 nav
參數即可。在這個情況下,我們將使用 page.nav
從 yaml frontmatter 中擷取它。
{% include nav.html nav=page.nav %}
我們的包含檔會先使用這個,然後檢視每個項目的 subnav
屬性,以遞迴地呈現巢狀清單。
結果