Liquid、JavaScriptなどに関する質問
いつもフォーラムで的確な回答をありがとうございます。
ブログに目次(TOC)を別のサイトを参考にして導入しています。現状でも充分なのですが、文字数が多く比例して目次が多くなると、少し読みづらい印象のため、目次に開閉ボタンを付けたいと思っています。
調べるとJavaScriptに追加スクリプトを書くまでは理解できましたが、その先に進めません。
解決のお力をお願いしたいです、よろしくお願いします。コードは下記となります。
toc.js
{ const TOC_INSERT_SELECTOR = '#toc'; const HEADING_SELECTOR = 'h1,h2,h3,h4,h5,h6'; const LINK_CLASS_NAME = 'tocLink'; const ID_NAME = 'heading'; const tocInsertElement = document.querySelector(TOC_INSERT_SELECTOR); const tocTarget = document.querySelector('#toc_target'); const headingElements = tocTarget.querySelectorAll(HEADING_SELECTOR); const layer = []; let id = 0; const uid = () =>`${ID_NAME}${id++}`; let oldRank = -1; try { const createLink = (el) => { let li = document.createElement('li'); let a = document.createElement('a'); el.id = el.id || uid(); a.href = `#${el.id}`; a.innerText = el.innerText; a.className = LINK_CLASS_NAME; li.appendChild(a); return li; }; const findParentElement = (layer, rank, diff) => { do { rank += diff; if (layer[rank]) return layer[rank]; } while (0 < rank && rank < 7); return false; }; const appendToc = (el, toc) => { el.appendChild(toc.cloneNode(true)); }; headingElements.forEach( (el) => { let rank = Number(el.tagName.substring(1)); let parent = findParentElement(layer, rank, -1); if (oldRank > rank) layer.length = rank + 1; if (!layer[rank]) { layer[rank] = document.createElement('ol'); if (parent.lastChild) parent.lastChild.appendChild(layer[rank]); } layer[rank].appendChild(createLink(el)); oldRank = rank; }); if (layer.length) appendToc(tocInsertElement, findParentElement(layer, 0, 1)); } catch (e) { //error } }
toc.css
html { scroll-behavior: smooth; } #toc { padding: 1.5em; margin-bottom: 1em; border: 1px solid #ccc; } #toc ol { list-style: none; counter-reset: toc; padding-left: 2em; margin: 0; } #toc ol li::before { counter-increment: toc; content: counters(toc, "-"); display: inline; padding-right: .5em; margin-left: -2em; }
main-article.liquidに下記を追加しています。大幅に省略しています。
{% comment %}上部にcssを追記{% endcomment %} {{ 'toc.css' | asset_url | stylesheet_tag }} {% comment %}article.contentに以下を追記{% endcomment %} 〜 省略 〜 <div id="toc_target" class="article-template__content page-width page-width--narrow rte" itemprop="articleBody" {{ block.shopify_attributes }}> <div id="toc"></div> {{ article.content }} </div> 〜 省略 〜 <script src="{{ 'toc.js' | asset_url }}" defer></script>
開閉についてですが、htmlで開閉部分の記述を<details>にし、
JavaScripやCSSでdetailsの見た目を調整することで、実現できるのではと思われます。
https://developer.mozilla.org/ja/docs/Web/HTML/Reference/Elements/details
ご参考まで。
(キュー小坂)