すたすた式
Blogger QooQ
目次を自動作成(生成)するJavaScriptを書いてみました。
新しく見出しの数で目次の開閉を調整できる機能を追加してみました。よろしければどうぞ。
目次の自動作成のためのコードは見出しタグから入れ子の目次を自動作成するJavaScriptを作りました【コピペOK】 | まろりかさん。
スムーススクロールはjQueryを使わずにJavaScriptでスムーススクロールの実装方法! | Qumeruマガジンさんをそれぞれ参考、参照しました。ありがとうございます。
公式テーマ:ContempoとQooQ:Version:1.30で動作を確認しました。
詳しくは後述しますが、初期値は見出しの取得先と目次の出力先に.post-bodyを使っています。
.post-body
その他のテーマ(テンプレート)は見出しの取得先と目次の出力先の変更で利用可能だと考えています。
(必要なければCDATAセクション//<![CDATA[ //]]>は削除してください。)
//<![CDATA[
//]]>
デフォルトでは下記のような構成でHTMLが生成されます。
<div id="toc-wrapper" class="toc-wrapper"> <div id="toc-title" class="toc-title">目次</div> <ul id="toc-container" class="toc-container"> <li> <a href="#"></a> <ul> <li><a href="#"></a></li> </ul> </li> <li><a href="#"></a></li> </ul> </div>
非エンジニアが作成したものです。正確性は担保できなので留意してください。
HTMLを編集します。必ずバックアップを取ってから作業してください。
<script> // Reference /*! 目次 toc: https://www.marorika.com/entry/create-toc */ /*! スムーススクロール smoothscroll: https://qumeru.com/magazine/293 */ // Blogger用 //<![CDATA[ document.addEventListener("DOMContentLoaded", () => { /*------------------------------ 設定 start ------------------------------*/ const tocSetup = { // 見出しの取得先と目次の出力先 parent: ".post-body", // 目次を作成しないためのid名 noTocid: "no-toc", // 目次を作成しない条件用の要素を取得 findElements: "h2:not(details h2)", // 要素の数がこの数字以下だったら目次を作成しない numberOfelements: 2, // 見出しの取得 // .post-body以下の(details要素内のh2, h3要素を除く)h2, h3要素を全て取得 headings: "h2:not(details h2), h3:not(details h3)", // 目次のタイトル文字 tocTitletext: "目次", // 目次をどこに出力するか 例:.post-body以下の(details要素内のh2要素を除く)1番目のh2要素の上に出力 // 目次の出力先要素 例:(details要素内のh2要素を除く)h2要素 targetElement: "h2:not(details h2)", // 何番目の出力先要素に出力するか order: 1, // 目次の出力位置(1:出力先要素の上、2:出力先要素の下) position: 1, }; /*------------------------------ 設定 end ------------------------------*/ /*------------------------------ ここから目次を作成しない条件 ------------------------------*/ // id名no-tocがあったら目次を作成しない const noToc = document.getElementById(tocSetup.noTocid); if (noToc !== null) return; /* 例:.post-body以下のh2要素が2個以下だったら目次を作成しない -------------------------------------------------------*/ // .post-body以下のh2要素を全て取得 const findHeadings = document.querySelectorAll(tocSetup.findElements); // h2要素が2個以下だったら作成しない if (findHeadings.length <= tocSetup.numberOfelements) return; /*------------------------------ ここまで目次を作成しない条件 ------------------------------*/ // 目次が入るdiv要素を作成 const tocWrapper = document.createElement("div"); // id="toc-wrapper" を追加 tocWrapper.id = "toc-wrapper"; // class="toc-wrapper" を追加 tocWrapper.className = "toc-wrapper"; /*------------------------------ ここから目次のタイトル作成 ------------------------------*/ // タイトルが入るdiv要素を作成 const tocTitle = document.createElement("div"); // id="toc-title"を追加 tocTitle.id = "toc-title"; // class="toc-title"を追加 tocTitle.className = "toc-title"; // テキストを追加 tocTitle.textContent = tocSetup.tocTitletext; // 目次が入るdiv要素に出力 tocWrapper.appendChild(tocTitle); /*------------------------------ ここまで目次のタイトル作成 ------------------------------*/ // 目次コンテナ用にul要素を作成 const tocContainer = document.createElement("ul"); // id="toc-container" を追加 tocContainer.id = "toc-container"; // class="toc-container" を追加 tocContainer.className = "toc-container"; /*------------------------------ ここから目次を出力する場所を取得 ------------------------------*/ // 目次を入れる親要素を取得 const parentElement = document.querySelector(tocSetup.parent); // .post-body以下にある1個目のh2要素を取得 const target = parentElement.querySelectorAll(tocSetup.targetElement)[ tocSetup.order - 1 ]; /*------------------------------ ここまで目次を出力する場所を取得 ------------------------------*/ // .post-body以下の(details要素内のh2, h3要素を除いく)h2, h3要素を全て取得 const tocElements = parentElement.querySelectorAll(tocSetup.headings); // 取得した見出しタグ要素の数だけ以下の操作を繰り返す tocElements.forEach((value, i) => { // 見出しタグ要素のidを取得。空の場合は"見出しタイトル" + "_TOC-No." + "数字"をidにする let id = value.id; if (id === "") { id = value.textContent + "_TOC-No." + i; //id = i; // 数字のみ value.id = id; } // 要素がh2タグの場合 if (value.tagName === "H2") { const li = document.createElement("li"); const a = document.createElement("a"); a.textContent = value.textContent; a.href = "#" + value.id; li.appendChild(a); tocContainer.appendChild(li); } // 目次コンテナ用ul要素の最後の子要素を取得 const lastElement = tocContainer.lastElementChild; // 要素がh3タグかつ目次コンテナ用ul要素の最後の子要素がli要素の場合 if (value.tagName === "H3" && lastElement.tagName === "LI") { const ul = document.createElement("ul"); const li = document.createElement("li"); const a = document.createElement("a"); a.textContent = value.textContent; a.href = "#" + value.id; ul.appendChild(li); li.appendChild(a); lastElement.appendChild(ul); } // 要素がh3タグかつ目次コンテナ用ul要素の最後の子要素がul要素の場合 if (value.tagName === "H3" && lastElement.tagName === "UL") { const li = document.createElement("li"); const a = document.createElement("a"); a.textContent = value.textContent; a.href = "#" + value.id; li.appendChild(a); lastElement.appendChild(li); } }); // 目次コンテナ用ul要素を目次が入るdiv要素に出力 tocWrapper.appendChild(tocContainer); // 目次の出力位置(0:トップ、1:出力先の上、2:出力先の下) if (tocSetup.position === 0) { parentElement.prepend(tocWrapper); } else if (tocSetup.position === 1) { target.before(tocWrapper); } else if (tocSetup.position === 2) { target.after(tocWrapper); } /*------------------------------ ここからスムーススクロール ------------------------------*/ // ここにスムーススクロールのコードを貼り付ける /*------------------------------ ここまでスムーススクロール ------------------------------*/ }); //]]> </script>
下は説明ブロックがないバージョン。出来ることは同じです。
<script> // Reference /*! 目次 toc: https://www.marorika.com/entry/create-toc */ /*! スムーススクロール smoothscroll: https://qumeru.com/magazine/293 */ // Blogger用 //<![CDATA[ document.addEventListener("DOMContentLoaded", () => { // 見出しと目次の出力先を取得 //const parentElement = document.querySelector(".widget.Blog"); // 取得範囲が広い //const parentElement = document.getElementById("Blog1"); // 取得範囲が広い const parentElement = document.querySelector(".post-body"); /*------------------------------ ここから目次を作成しない条件 ------------------------------*/ // id名no-tocがあったら目次を作成しない const noToc = document.getElementById("no-toc"); if (noToc !== null) return; // .post-body以下の(details要素内のh2要素を除く)h2要素を全て取得 const findHeadings = parentElement.querySelectorAll("h2:not(details h2)"); // h2要素が2個以下だったら作成しない if (findHeadings.length <= 2) return; /*------------------------------ ここまで目次を作成しない条件 ------------------------------*/ // 目次が入るdiv要素を作成 const tocWrapper = document.createElement("div"); // id="toc-wrapper"を追加 tocWrapper.id = "toc-wrapper"; // class="toc-wrapper"を追加 tocWrapper.className = "toc-wrapper"; /*------------------------------ ここから目次のタイトル作成 ------------------------------*/ // タイトルが入るdiv要素を作成 const tocTitle = document.createElement("div"); // id="toc-title"を追加 tocTitle.id = "toc-title"; // class="toc-title"を追加 tocTitle.className = "toc-title"; // テキストを追加 tocTitle.textContent = "目次"; // 目次が入るdiv要素に出力 tocWrapper.appendChild(tocTitle); /*------------------------------ ここまで目次のタイトル作成 ------------------------------*/ // 目次コンテナ用にul要素を作成 const tocContainer = document.createElement("ul"); // id="toc-container"を追加 tocContainer.id = "toc-container"; // class="toc-container"を追加 tocContainer.className = "toc-container"; /*------------------------------ ここから目次を出力する場所を取得 ------------------------------*/ // .post-body以下の(details要素内のh2要素を除く)1個目のh2要素を取得 const target = parentElement.querySelectorAll("h2:not(details h2)")[0]; // .post-body以下の1個目のh2要素を取得 //const target = parentElement.querySelectorAll("h2")[0]; /*------------------------------ ここまで目次を出力する場所を取得 ------------------------------*/ // .post-body以下の(details要素内のh2, h3要素を除く)h2,h3要素を全て取得 const tocElements = parentElement.querySelectorAll( "h2:not(details h2), h3:not(details h3)" ); // .post-body以下のh2, h3要素をすべて取得 //const tocElements = parentElement.querySelectorAll("h2, h3"); // 取得した見出しタグ要素の数だけ以下の操作を繰り返す tocElements.forEach((value, i) => { // 見出しタグ要素のidを取得。空の場合は"見出しタイトル" + "_TOC-No." + "数字"をidにする let id = value.id; if (id === "") { id = value.textContent + "_TOC-No." + i; //id = i; // 数字のみ value.id = id; } // 要素が h2 タグの場合 if (value.tagName === "H2") { const li = document.createElement("li"); const a = document.createElement("a"); a.textContent = value.textContent; a.href = "#" + value.id; li.appendChild(a); tocContainer.appendChild(li); } // 目次コンテナ用 ul 要素の最後の子要素を取得 const lastElement = tocContainer.lastElementChild; // 要素が h3 タグかつ目次コンテナ用 ul 要素の最後の子要素が li 要素の場合 if (value.tagName === "H3" && lastElement.tagName === "LI") { const ul = document.createElement("ul"); const li = document.createElement("li"); const a = document.createElement("a"); a.textContent = value.textContent; a.href = "#" + value.id; ul.appendChild(li); li.appendChild(a); lastElement.appendChild(ul); } // 要素が h3 タグかつ目次コンテナ用 ul 要素の最後の子要素が ul 要素の場合 if (value.tagName === "H3" && lastElement.tagName === "UL") { const li = document.createElement("li"); const a = document.createElement("a"); a.textContent = value.textContent; a.href = "#" + value.id; li.appendChild(a); lastElement.appendChild(li); } }); // 目次コンテナ用ul要素を目次が入るdiv要素に出力 tocWrapper.appendChild(tocContainer); // .post-body以下にある1個目のh2要素の上に目次を出力 target.before(tocWrapper); // .post-body以下にある1個目のh2要素の下に目次を出力 //target.after(tocWrapper); // .post-body 以下の最初の要素として目次を出力(記事・ページのトップに出力される) // parentElement.prepend(tocWrapper); // ここからスムーススクロール // ここにスムーススクロールのコードを貼り付ける // ここまでスムーススクロール }); //]]> </script>
id="no-toc"
目次を作成するかしないかは、h2要素の数で判断しています。したがって長い記事でも、h2要素が少ないと目次が作成されません。反対に、短い記事でもh2要素が多いと目次が作成されます。:(
全体に対しての調整は可能ですが各記事、各ページごとの調整はできません。(id="no-toc"の要素がある記事・ページに目次を作成しない機能は有効)
過去記事にも一括適用されるので、記事の構成によっては目次が不自然な場所に出力されてしまいます。
作成されるidと同じidがすでに記事・ページに存在する場合クリックしても見出しまで移動しません。(挙動が不安定)
最初h2要素の前にh3要素があると目次が作成されません。
<h3>h3要素の見出し</h3> <h2>最初のh2要素の見出し</h2>
閉じた状態のdetails要素内にh2, h3要素があると、目次は作成されますがクリックしても見出しまで移動しませんでした。
そのため初期値ではdetails要素内のh2, h3要素は取得しないようになっています。(変更可能)
<details>: 詳細折りたたみ要素 - HTML: HyperText Markup Language | MDN
初期値ではdetails要素内のh2要素は取得しないようになっています。(変更可能)
したがってdetails要素外にある任意の順番のh2要素を目標にして目次が出力されます。
</head>の上か、</body>の上あたりにコピペしてください。(とくに問題がなければ</body>の直上でいいと思います。)
</head>
</body>
スムーススクロールの部分はQumeruマガジンさんが公開しているコードを使用させてもらいました。ここにスムーススクロールのコードを貼り付けるのところにリンク先のコードを貼り付けると動作します。
また、対応ブラウザが限られますがCSSでもスムーススクロールが可能です。
html { scroll-behavior: smooth; }
CSSを貼り付ける位置がよくわからないときは]]></b:skin>の上に貼り付けてください。(Bloggerの場合)
]]></b:skin>
コード内の数字や要素の変更をすることで、自分好みにカスタマイズできます。
見出しの取得と目次の出力先に使う要素を取得します。
具体的には記事やページの親要素を取得します。
お使いのテーマ(テンプレート)をデベロッパーツールなどで確認してください。
たとえば下記のような構成になっていたら.entry-contentsと指定してください。
.entry-contents
<div class="entry-contents"> <p>文章</p> <h2>見出し</h2> <p>文章</p> </div>
parent: ".entry-contents",
Bloggerで使用するにあたって、ある程度の汎用性を考慮して初期値は.post-bodyを使っています。
初期値はh2要素が2個以下の場合は目次を作成しないようになっています。
まず条件に使う要素を取得します。
初期値は.post-body以下の(details要素内のh2要素を除く)h2要素です。
findElements: "h2:not(details h2)",
次に条件に使う要素の数を設定します。
h2要素が5個以下だったら目次を作成したくない場合、数字を5に変更します。
numberOfelements: 2, ↓ numberOfelements: 5,
記事内にid名no-tocの要素があると目次が作成されません。
たとえば<div id="no-toc">~</div>で記事やページ全体をラップすると、その記事・ページには目次が作成されません。
<div id="no-toc">~</div>
<div id="no-toc"> 記事・ページの内容 </div>
また、id名no-tocが不都合な場合、任意ものに変更できます。
noTocid: "no-toc", ↓ noTocid: "not-create-toc",
初期値は.post-body以下にある(details要素内のh2, h3要素を除く)h2, h3要素を取得しています。
details要素内のh2, h3要素も取得したい場合下記のようにしてください。
headings: "h2:not(details h2), h3:not(details h3)", ↓ headings: "h2, h3",
目次タイトルを変更できます。
tocTitletext: "目次", ↓ tocTitletext: "もくじ",
CSSの擬似要素beforeでタイトルをつける場合や、タイトルそのものがいらない場合は、tocTitletext: "目次",と // ここから目次のタイトル作成から// ここまで目次のタイトル作成を削除してください。
tocTitletext: "目次",
// ここから目次のタイトル作成
// ここまで目次のタイトル作成
CSS擬似要素の例
.toc-container::before { content: "目次"; }
目次の出力先要素を指定します。
初期値は.post-body以下にある1番目のh2要素の上に出力します。
はじめに、.post-body以下の目標の要素(details要素内のh2要素を除くh2要素)、"h2:not(details h2)"をすべて取得します。
"h2:not(details h2)"
targetElement: "h2:not(details h2)",
次に、何番目の要素に出力するか指定します。(初期値は1番目)
order: 1,
2番目を指定する場合は数字を変更してください。
order: 1, ↓ order: 2,
ここまでで、.post-body以下の1番目のh2要素まで指定できました。
最後に、目標の要素から見てどこに出力するかを指定します。
目標の要素の上に出力
position: 1
目標の要素の下に出力
position: 2
記事の一番上に出力
position: 0
出力先を記事の一番上を指定した場合、取得した.post-body以下の1番目のh2要素は無視されます。
const gap = 60;の行の数字変更でスクロール後の画面上部と要素の間隔を調整できます。
const gap = 60;
目次が入るdiv要素をdetails要素に、タイトルが入るdiv要素をsummary要素にそれぞれ変更すると目次を開閉できるようになります。
// 目次が入るdiv要素を作成 const tocWrapper = document.createElement("div"); ↓ const tocWrapper = document.createElement("details");
// タイトルが入るdiv要素を作成 const tocTitle = document.createElement("div"); ↓ const tocTitle = document.createElement("summary");
目次を開いた状態で表示させたい場合はtocWrapper.open = true;を追加してください。
tocWrapper.open = true;
// 目次が入るdiv要素を作成 const tocWrapper = document.createElement("details"); // id="toc-wrapper"を追加 tocWrapper.id = "toc-wrapper"; // class="toc-wrapper"を追加 tocWrapper.className = "toc-wrapper"; tocWrapper.open = true; // ← 追加
CSSの例です
.toc-title { font-weight: bold; text-align: center; } #toc-container li { line-height: 2; } /* details,summary要素で展開 */ details { margin: 0.5em 0; } summary { padding: 0 1em; background: #e2f0f7; list-style: none; cursor: pointer; } summary::-webkit-details-marker { display: none; } summary:hover { background: #badbec; } details[open] * { animation: fadein 0.4s ease; } @keyframes fadein { 0% { opacity: 0; } 100% { opacity: 1; } } details summary::before { margin-right: 0.25em; color: #aaa; font-weight: bold; font-size: 1.5em; font-family: SFMono-Regular, Consolas, "Courier New", monospace; content: "+"; } details[open] summary::before { content: "-"; }
目次に番号が必要な場合、コード内のul要素をol要素に変更するか、CSSでカウンターを使えばある程度表現できると思います。(丸投げ)
貼り付けただけだとページ(固定ページ)にも目次が表示されます。
投稿(記事ページ)のみに表示させたい場合は、コード全体を<b:if cond='data:blog.pageType == "item"'>...</b:if>や<b:if cond='data:view.isPost'>...</b:if>で囲んでください。
<b:if cond='data:blog.pageType == "item"'>...</b:if>
<b:if cond='data:view.isPost'>...</b:if>
<b:if cond='data:blog.pageType == "item"'> コード </b:if>
作成(生成)されるコードのid名やclass名に不都合がある場合任意のものに変更してください。
また、必要ない場合は削除してください。
このようなところです。
// id="toc-wrapper"を追加 tocWrapper.id = "toc-wrapper"; // class="toc-wrapper"を追加 tocWrapper.className = "toc-wrapper";
一例です(簡素なものです)
.toc-wrapper { border-top: 4px solid #eee; border-bottom: 2px solid #eee; } .toc-title { text-align: center; font-weight: bold; } #toc-container li { line-height: 2; }
Bloggerで使用するにあたり、ある程度の汎用性を考慮して、見出しの取得先と目次の出力先の取得には、.post-bodyをつかいました。
Contempo, Soho, Emporio, Notable, Essential, Simple,QooQは見出しの取得先と目次の出力先要素のclassにpost-bodyがあるので初期値のまま使えます。
以下、見出しの取得先と目次の出力先要素です。
<div class="post-body entry-content float-container" id="post-body-xxxxxxxxxxxxxxxxxxx">
Soho, Emporio, Notable, Essentialも同じ要素でした。
id="post-body-xxxxxxxxxxxxxxxxxxx"のxは記事毎に変化するっぽい?。
id="post-body-xxxxxxxxxxxxxxxxxxx"
x
<div class="post-body entry-content" id="post-body-xxxxxxxxxxxxxxxxxxx" itemprop="description articleBody">
<div class="post-body" id="single-content">
QooQにはid="single-content"があるので、#single-contentとしたり、使える場所では、
id="single-content"
#single-content
getElementById();
を使ってもいいかもしれません。
Smart 、Hello, world!は目次作成機能を実装済みです。
当テンプレートには自動目次機能が標準搭載されています。これは仕様によって有無を選ぶことができます。 Smart
一応調べた結果
<div class="post-content">
その他のテーマはデベロッパーツールなどをつかって見出しの取得先と目次の出力先を調べてください。
記事公開時のものです。
目次以外でもスムーススクロールを使いたかったので、スムーススクロールのコードをdocument.addEventListener("DOMContentLoaded", function () {...});で囲んで別のスクリプトとして運用することにしました。
document.addEventListener("DOMContentLoaded", function () {...});
<script> //<![CDATA[ document.addEventListener("DOMContentLoaded", function () { スムーススクロールのコード }); //]]> </script>
それと変数名を変更しました。
<script> // Reference /*! 目次 toc: https://www.marorika.com/entry/create-toc */ // Blogger用 //<![CDATA[ document.addEventListener("DOMContentLoaded", () => { // 見出しの取得先と目次の出力先親要素を取得 const parentElement = document.getElementById("single-content"); /*------------------------------ ここから目次を作成しない条件 ------------------------------*/ // id名no-tocがあったら目次を作成しない const noToc = document.getElementById("no-toc"); if (noToc !== null) return; // .post-body以下の(details要素内のh2要素を除く)h2要素を全て取得 const findHeadings = parentElement.querySelectorAll("h2:not(details h2)"); // h2要素が2個以下だったら作成しない if (findHeadings.length <= 2) return; /*------------------------------ ここまで目次を作成しない条件 ------------------------------*/ // 目次が入るdiv要素を作成 const tocWrapper = document.createElement("div"); // id="toc-wrapper"を追加 tocWrapper.id = "toc-wrapper"; // class="toc-wrapper"を追加 tocWrapper.className = "toc-wrapper"; /*------------------------------ ここから目次のタイトル作成 ------------------------------*/ // タイトルが入るdiv要素を作成 const tocTitle = document.createElement("div"); // id="toc-title"を追加 tocTitle.id = "toc-title"; // class="toc-title"を追加 tocTitle.className = "toc-title"; // テキストを追加 tocTitle.textContent = "目次"; // 目次が入るdiv要素に出力 tocWrapper.appendChild(tocTitle); /*------------------------------ ここまで目次のタイトル作成 ------------------------------*/ // 目次コンテナ用にul要素を作成 const tocContainer = document.createElement("ul"); // id="toc-container"を追加 tocContainer.id = "toc-container"; // class="toc-container"を追加 tocContainer.className = "toc-container"; /*------------------------------ ここから目次を出力する場所を取得 ------------------------------*/ // .post-body以下の(details要素内のh2要素を除く)1個目のh2要素を取得 const target = parentElement.querySelectorAll("h2:not(details h2)")[0]; // .post-body以下の1個目のh2要素を取得 //const target = parentElement.querySelectorAll("h2")[0]; /*------------------------------ ここまで目次を出力する場所を取得 ------------------------------*/ // .post-body以下の(details要素内のh2, h3要素を除く)h2,h3要素を全て取得 const tocElements = parentElement.querySelectorAll( "h2:not(details h2), h3:not(details h3)" ); // .post-body以下のh2, h3要素をすべて取得 //const tocElements = parentElement.querySelectorAll("h2, h3"); // 取得した見出しタグ要素の数だけ以下の操作を繰り返す tocElements.forEach((value, i) => { // 見出しタグ要素のidを取得。空の場合は"見出しタイトル" + "_TOC-No." + "数字"をidにする let id = value.id; if (id === "") { id = value.textContent + "_TOC-No." + i; //id = i; // 数字のみ value.id = id; } // 要素が h2 タグの場合 if (value.tagName === "H2") { const li = document.createElement("li"); const a = document.createElement("a"); a.textContent = value.textContent; a.href = "#" + value.id; li.appendChild(a); tocContainer.appendChild(li); } // 目次コンテナ用 ul 要素の最後の子要素を取得 const lastElement = tocContainer.lastElementChild; // 要素が h3 タグかつ目次コンテナ用 ul 要素の最後の子要素が li 要素の場合 if (value.tagName === "H3" && lastElement.tagName === "LI") { const ul = document.createElement("ul"); const li = document.createElement("li"); const a = document.createElement("a"); a.textContent = value.textContent; a.href = "#" + value.id; ul.appendChild(li); li.appendChild(a); lastElement.appendChild(ul); } // 要素が h3 タグかつ目次コンテナ用 ul 要素の最後の子要素が ul 要素の場合 if (value.tagName === "H3" && lastElement.tagName === "UL") { const li = document.createElement("li"); const a = document.createElement("a"); a.textContent = value.textContent; a.href = "#" + value.id; li.appendChild(a); lastElement.appendChild(li); } }); // 目次コンテナ用ul要素を目次が入るdiv要素に出力 tocWrapper.appendChild(tocContainer); // .post-body以下にある1個目のh2要素の上に目次を出力 target.before(tocWrapper); // .post-body以下にある1個目のh2要素の下に目次を出力 //target.after(tocWrapper); // .post-body 以下の最初の要素として目次を出力(記事・ページのトップに出力される) // parentElement.prepend(tocWrapper); // ここからスムーススクロール // ここにスムーススクロールのコードを貼り付ける // ここまでスムーススクロール }); //]]> </script> <script> // Reference /*! スムーススクロール smoothscroll: https://qumeru.com/magazine/293 */ //<![CDATA[ document.addEventListener("DOMContentLoaded", function () { const triggerSelector = document.querySelectorAll('a[href^="#"]'); for (let i = 0; i < triggerSelector.length; i++) { triggerSelector[i].addEventListener("click", (e) => { e.preventDefault(); let href = triggerSelector[i].getAttribute("href"); let targetElement = document.getElementById(href.replace("#", "")); const topEdgescreen = targetElement.getBoundingClientRect().top; const scrollAmount = window.pageYOffset; const space = 10; // 上の空間調整 0で上に貼り付く const target = topEdgescreen + scrollAmount - space; window.scrollTo({ top: target, behavior: "smooth", }); }); } }); //]]> </script>
当初、汎用性を考慮してBloggerのテーマ(テンプレート)共通であろう.widget.Blogや#Blog1を見出しの取得先と目次の出力先要素として指定しました。
.widget.Blog
#Blog1
しかし、公式テーマContempoやSimpleで目次が作成されませんでした。
Contempoは記事タイトルにh3タグが使われていて、これも取得してしまうのが原因のようです。(コメントにもh3タグが使われていました。)
<h3 class="post-title entry-title"> 記事タイトル </h3>
<h3 class="title" id="コメント">コメント</h3>
Simpleは記事タイトルにh3タグが使われ、公開日にh2タグが使われていました。
<h3 class="post-title entry-title" itemprop="name"> 記事タイトル </h3>
<h2 class="date-header" id="xxxx年xx月xx日"><span>xxxx年xx月xx日</span></h2>
そのため次善の策として.post-bodyを使用しました。
下記は作成過程で調べたものです。親要素が.widget.BlogのときにComtempo, Simpleで使用する際の設定です。
parent: ".widget.Blog",
findElements: "h2:not(details h2):not(.date-header)",
headings: "h2:not(details h2):not(.date-header), h3:not(details h3):not(.post-title.entry-title):not(.title)",
targetElement: "h2:not(details h2):not(.date-header)",
サイト内検索に使ってください 🐤
© 2015 すたすた式
Enjoy!👍
QooQ
コメントなし:
コメントを投稿