Webflow CMS 上的動態目錄 - 最簡單的方法

已發表: 2022-03-22
我們最近可以將活動狀態添加到粘性目錄中 - 請參閱文章末尾的說明!

背景

在 Flowrite,我們最近開始編寫更長的內容片段,並希望從最基本的元素——目錄開始,讓我們的博客更具可讀性。

我們正在使用 Webflow 並且非常喜歡它,但事實證明,為 CMS 項目創建可擴展的 ToC 並不是那麼簡單。 所有現有的解決方案都依賴於手動設置 id 和鏈接或使用 3rd-party 插件。

我們想要一個簡單的系統,可以根據我們博客中的標題自動生成 ToC。 這就是我們構建的,這就是你如何做同樣的事情!

這個怎麼運作?

  1. 設計您的 ToC 項目。 以任何你想要的方式製作它們——創建懸停狀態、動畫等。
  2. 在 CMS 頁面上的任何位置為 ToC 創建一個具有特定 ID 的 div。
  3. 在您的 CMS 頁面上的 <body> 標記末尾插入一段代碼。
  4. 為每個 CMS 項目自動生成 ToC。

創建動態目錄

設計您的 ToC 項目

給你的 ToC 項目一個類(我們使用“tocitem”)並以你想要的任何方式設置它。

我的建議是使用單獨的私有頁面來設計這些元素。 這樣,您以後可以在需要時輕鬆修改設計。

我們喜歡 Notion 目錄元素的簡單性,因此我們將其用作基準。


如果您想包含不止一種類型的標題,請確保給它們一個額外的類(“toc-h2”、“toc-h3”等)

為您的 ToC 創建元素

在您希望 ToC 所在的任何位置添加一個 div,並為其指定一個 id “toc”。 同樣,您可以根據需要為該元素設置任何樣式。

如果您希望將 ToC 包含在富文本元素中,請參閱本文末尾以獲取更多詳細信息。

最後,給 Rich Text 元素一個 id “content”。 稍後將需要這樣做,以確保我們在 ToC 中使用正確的標題。

從兩個選項中選擇

由於 ToC 將自動生成,因此我們需要指明要包含在其中的標題。 在這篇文章中,我們介紹了兩個選項:

  1. 僅基於單個靜態標題類型生成 ToC,例如 H2s。
  2. 根據您選擇的多個標題生成 ToC——例如,一篇博文的 H2 和 H3 以及另一篇博文的 H2 和 H4。

選項 1:單標題 ToC

在此選項中,將始終基於相同的標題生成 ToC。

在集合頁面上的 <body> 標記末尾插入以下代碼。 如果您想了解它是如何工作的,請參閱每行末尾的註釋。

  <script> document.getElementById("content").querySelectorAll("h2").forEach(function(heading, i) { // runs a function for all h2 elements inside your rich text element heading.setAttribute("id", "toc-" + i); // gives each h2 a unique id let str = heading.innerHTML; // adds section titles to slugs str = str.replace(/\s+/g, '-').replace(/[°&\/\\#,+()$~%.'":;*?<>{}]/g, "").toLowerCase(); // replaces spaces with hyphens, removes special characters and extra spaces from the headings, and applies lowercase in slugs heading.setAttribute("id", str); // gives each heading a unique id const item = document.createElement("a"); // creates an anchor element called "item" for each h2 item.innerHTML = heading.innerHTML // gives each item the text of the corresponding heading item.setAttribute("class", "tocitem"); // gives each item the correct class item.setAttribute("href", "#" + str); // gives each item the correct anchor link document.querySelector("#toc").appendChild(item); // places each item inside the Table of Contents div }); </script>
<script> document.getElementById("content").querySelectorAll("h2").forEach(function(heading, i) { // runs a function for all h2 elements inside your rich text element heading.setAttribute("id", "toc-" + i); // gives each h2 a unique id let str = heading.innerHTML; // adds section titles to slugs str = str.replace(/\s+/g, '-').replace(/[°&\/\\#,+()$~%.'":;*?<>{}]/g, "").toLowerCase(); // replaces spaces with hyphens, removes special characters and extra spaces from the headings, and applies lowercase in slugs heading.setAttribute("id", str); // gives each heading a unique id const item = document.createElement("a"); // creates an anchor element called "item" for each h2 item.innerHTML = heading.innerHTML // gives each item the text of the corresponding heading item.setAttribute("class", "tocitem"); // gives each item the correct class item.setAttribute("href", "#" + str); // gives each item the correct anchor link document.querySelector("#toc").appendChild(item); // places each item inside the Table of Contents div }); </script>

發佈網站,一切順利

選項 2:多標題 ToC

此選項使您有機會根據具體情況確定將使用哪些標題來生成 ToC。

讓我們首先在您的收藏中創建一個新的文本字段。 我們稱其為“基於...的 TOC”。 您可以在此處指定將在每個 CMS 項目的 ToC 中使用的標題。 用逗號分隔,不要包含任何空格。


現在,在集合頁面上的 <body> 標記末尾插入以下代碼。 如果您想了解它是如何工作的,請參閱每行末尾的註釋。

  <script> document.getElementById("content").querySelectorAll("[HEADINGS]").forEach(function(heading, i) { // runs a function for all headings inside your rich text element let str = heading.innerHTML; // adds section titles to slugs str = str.replace(/\s+/g, '-').replace(/[°&\/\\#,+()$~%.'":;*?<>{}]/g, "").toLowerCase(); // replaces spaces with hyphens, removes special characters and extra spaces from the headings, and applies lowercase in slugs heading.setAttribute("id", str); // gives each heading a unique id const item = document.createElement("a"); // creates an anchor element called "item" for each heading item.innerHTML = heading.innerHTML; // gives each item the text of the corresponding heading ("[HEADINGS]").split(",").forEach(function(x) { // runs a function for each item in your headings list if (heading.tagName.toLowerCase()==x) { item.classList.add("tocitem", "toc-" + x); // gives each item the correct class } }); item.setAttribute("href", "#" + str); // gives each item the correct anchor link document.querySelector("#toc").appendChild(item); // places each item inside the Table of Contents div }); </script>
<script> document.getElementById("content").querySelectorAll("[HEADINGS]").forEach(function(heading, i) { // runs a function for all headings inside your rich text element let str = heading.innerHTML; // adds section titles to slugs str = str.replace(/\s+/g, '-').replace(/[°&\/\\#,+()$~%.'":;*?<>{}]/g, "").toLowerCase(); // replaces spaces with hyphens, removes special characters and extra spaces from the headings, and applies lowercase in slugs heading.setAttribute("id", str); // gives each heading a unique id const item = document.createElement("a"); // creates an anchor element called "item" for each heading item.innerHTML = heading.innerHTML; // gives each item the text of the corresponding heading ("[HEADINGS]").split(",").forEach(function(x) { // runs a function for each item in your headings list if (heading.tagName.toLowerCase()==x) { item.classList.add("tocitem", "toc-" + x); // gives each item the correct class } }); item.setAttribute("href", "#" + str); // gives each item the correct anchor link document.querySelector("#toc").appendChild(item); // places each item inside the Table of Contents div }); </script>

最後,確保將 [HEADINGS] 替換為“ToC based on...”CMS 字段的值。


就是這樣,您已準備好發布。

定制

粘性目錄中的活動狀態

受 Chris Coyier 在 CSS-Tricks 上的帖子的啟發,我們構建了一種將活動狀態添加到可見 ToC 項目的方法——這是粘性 ToC 的一個很好的功能。

首先,添加“observer.observe(heading);” 在您之前實現的代碼的開頭。 請參閱屏幕截圖以了解正確的位置。

然後,在所有現有 ToC 代碼之上添加以下代碼片段:

  <script> const observer = new IntersectionObserver(entries => { entries.forEach(entry => { const id = entry.target.getAttribute("id"); if (entry.isIntersecting) { document.querySelectorAll(".active").forEach((z) => { z.classList.remove("active") }); document.querySelector(`a[href="#${id}"]`).classList.add("active"); } }); }, { rootMargin: '0px 0px -75% 0px' }); </script>
<script> const observer = new IntersectionObserver(entries => { entries.forEach(entry => { const id = entry.target.getAttribute("id"); if (entry.isIntersecting) { document.querySelectorAll(".active").forEach((z) => { z.classList.remove("active") }); document.querySelector(`a[href="#${id}"]`).classList.add("active"); } }); }, { rootMargin: '0px 0px -75% 0px' }); </script>

該代碼將一個名為“active”的類添加到可見的 tocitem 並在出現新的 tocitem 時刪除該類。

最後,確保通過賦予不同的背景顏色來設置“活動”類的樣式。

僅在某些 CMS 項目上顯示 ToC

如果您不希望 ToC 出現在某些 CMS 項目上,請完成以下步驟:

‍ 1. 將“ToC based on..”字段留空。
如果您使用選項 1,請在 CMS 集合中添加一個開關,以指示是否應顯示 ToC。

2. 根據步驟 1 中的選擇器使 ToC div 的可見性成為條件

3. 在 ToC 代碼片段的開頭創建 if 語句,以避免在字段為空時運行函數。 記得用“}”結束。

富文本元素中的 ToC

如果要將 ToC 放在富文本元素中,可以使用嵌入代碼複製 ToC div 元素。

在您的富文本中創建一個自定義代碼元素,然後在代碼字段中復制並粘貼“<div id="toc" class="toc"></div>”。


如果您只想在某些 CMS 項目上使用內聯 ToC,而在其他項目上使用“正常”ToC,則需要做一些額外的技巧:

1. 創建一個只有一個選項的選項選擇器:“.getElementById('content')。在您希望在富文本中包含 ToC 的那些 CMS 項目上選擇它。

2. 僅當未設置選擇器時才顯示“正常”ToC。


3.將選擇器的值添加到代碼的以下部分。 現在,如果選擇器已被選中,代碼會將 ToC 項附加到正確的 ToC div 中。

避免滾動時導航欄覆蓋

您可能會注意到,單擊 ToC 鏈接時,頁面會向下滾動到正確的標題,但會被導航欄擋住。

要解決這個問題:

  1. 確保導航元素的位置設置為“固定”
  2. 將導航元素的標籤更改為“標題”

而已! 如果您在此過程中遇到任何問題,請隨時給我發送電子郵件或通過 Twitter / LinkedIn 聯繫。

我也很想知道你是否最終使用了這個系統,所以如果你這樣做了,請聯繫我,並與可能從中受益的其他人分享帖子️