Webflow CMSの動的目次–最も簡単な方法

公開: 2022-03-22
最近、スティッキーな目次にアクティブ状態を追加できるようになりました。手順については、記事の最後を参照してください。

バックグラウンド

Flowriteでは、最近、より長いコンテンツを書き始め、最も基本的な要素である目次から始めて、ブログを読みやすくしたいと考えていました。

私たちはWebflowを使用しており、絶対に気に入っていますが、CMSアイテム用にスケーラブルにToCを作成するのはそれほど簡単ではないことがわかりました。 既存のソリューションはすべて、IDとリンクを手動で設定するか、サードパーティのプラグインを使用することに依存しています。

ブログの見出しに基づいてToCを自動的に生成するシンプルなシステムが必要でした。 それが私たちが構築したものであり、これがあなたが同じことをする方法です!

使い方?

  1. ToCアイテムをデザインします。 それらを好きなように作成します–ホバー状態やアニメーションなどを作成します。
  2. CMSページの任意の場所に特定のIDを持つToCのdivを作成します。
  3. CMSページの<body>タグの最後にコードを挿入します。
  4. ToCは、CMSアイテムごとに自動的に生成されます。

動的な目次の作成

ToCアイテムをデザインする

ToCアイテムにクラスを付け(「tocitem」を使用)、好きなようにスタイルを設定します。

これらの要素を設計するには、別のプライベートページを使用することをお勧めします。 そうすれば、必要に応じて後で簡単にデザインを変更できます。

Notionの目次要素のシンプルさが気に入ったので、それをベンチマークとして使用しました。


複数の種類の見出しを含める場合は、必ず追加のクラス( "toc-h2"、 "toc-h3"など)を付けてください。

ToCの要素を作成します

ToCを配置する場所にdivを追加し、IDを「toc」にします。 この場合も、この要素のスタイルを自由に設定できます。

ToCをリッチテキスト要素内に配置する場合、詳細については、この記事の最後を参照してください。

最後に、リッチテキスト要素にID「コンテンツ」を指定します。 これは、目次で正しい見出しを使用していることを確認するために後で必要になります。

2つのオプションから選択

ToCは自動的に生成されるため、どの見出しを含めるかを指定する必要があります。 この投稿では、2つのオプションについて説明します。

  1. H2などの単一の静的見出しタイプのみに基づいてToCを生成します。
  2. 選択した複数の見出しに基づいてToCを生成します。たとえば、あるブログ投稿の場合はH2とH3、別のブログ投稿の場合はH2とH4です。

オプション1:単一見出しの目次

このオプションでは、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の生成に使用される見出しをケースバイケースで決定できます。

コレクションに新しいテキストフィールドを作成することから始めましょう。 これを「...に基づく目次」と呼びます。 ここで、各CMSアイテムの目次で使用される見出しを指定します。 カンマで区切り、スペースを含めないでください。


次に、コレクションページの<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]を「ToCbasedon...」CMSフィールドの値に置き換えてください。


これで、公開する準備が整いました。

カスタマイズ

スティッキーな目次のアクティブな状態

CSS-Tricksに関するChrisCoyierの投稿に触発されて、表示されている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>

このコードは、表示されているtocitemに「active」というクラスを追加し、新しいtocitemが表示されたときにそのクラスを削除します。

最後に、たとえば、「アクティブ」クラスに別の背景色を付けてスタイルを設定してください。

一部のCMSアイテムにのみToCを表示する

一部のCMSアイテムにToCを表示したくない場合は、次の手順を実行します。

‍1。「ToCbasedon..」フィールドは空のままにします。
オプション1を使用している場合は、CMSコレクションにスイッチを追加して、目次を表示するかどうかを指定します。

2.手順1のセレクターに基づいて、ToCdivの可視性を条件付きにします。

3.フィールドが空の場合に関数が実行されないように、ToCコードスニペットの先頭にifステートメントを作成します。 「}」で閉じることを忘れないでください。

リッチテキスト要素内のToC

ToCをリッチテキスト要素内に配置する場合は、埋め込みコードを使用してToCdiv要素を複製できます。

リッチテキスト内にカスタムコード要素を作成し、コードフィールドに「<divid = "toc" class = "toc"></div>」をコピーして貼り付けます。


一部のCMSアイテムにのみインラインToCを設定し、他のアイテムに「通常の」ToCを設定する場合は、いくつかの追加のトリックを実行する必要があります。

1.オプションセレクターを1つだけ作成します: "。getElementById('content')。リッチテキスト内に目次を含めるCMSアイテムで選択します。

2.セレクターが設定されていない場合にのみ、「通常の」ToCを表示します。


3.セレクターの値をコードの次の部分に追加します。 これで、セレクターが選択されている場合、コードは正しいToCdiv内にToCアイテムを追加します。

スクロールでのナビゲーションバーのオーバーレイは避けてください

ToCリンクをクリックすると、ページが正しい見出しまでスクロールダウンしますが、ナビゲーションバーによってブロックされることに気付くかもしれません。

これを修正するには:

  1. nav要素の位置が「固定」に設定されていることを確認してください
  2. nav要素のタグを「Header」に変更します

それでおしまい! 途中で問題が発生した場合は、遠慮なく私にメールを送信するか、Twitter/LinkedIn経由で連絡してください。

あなたがこのシステムを使用することになったのかどうかも知りたいので、使用した場合は私にpingして、それから利益を得る可能性のある他の誰かと投稿を共有してください️