目次を自作してみた

公開
目次を自作してみた

Shopifyのデフォルトでは目次の機能がない

アプリをインストールすれば目次の機能がつけれたりしますが

無料の範囲だとブランド名が表示されたりしてちょっとイマイチですよね。。

 

無料でオリジナルデザインの目次を使いたいと思い今回作ってみました。

動作については実際に上にある目次を触っていただければと思います。

 

今回書いたコードはこちら

// 目次制作
{
    document.addEventListener('DOMContentLoaded', function() {
        //目次を設置する場所を作る
        const articleContent = document.querySelector('.article-template__content');
        articleContent.insertAdjacentHTML('afterbegin', `
            <div class="tableContent-wrapper">
                <div id="tableContent" class="tableContent">
                    <div class="tableContent-title">
                        目次
                    </div>
                </div>
            </div> `
        );
        const article = document.querySelector('.article-template');
        const blogIndex = article.querySelector('#tableContent'); //目次の出力場所

        const headingArray = article.querySelectorAll('h2,h3'); 
        let h2Number = 1;
        let h3Number = 1;
        let h3Id = 1;
        headingArray.forEach((heading) => {
            let tag = heading.tagName;
            let headingText = heading.textContent;
            heading.className = 'blog-heading';
            if (tag == 'H2') {
                heading.id = 'id2-' + h2Number;
                let p = document.createElement('p');
                let a = document.createElement('a');
                p.insertAdjacentHTML('afterbegin', `<span class="indexNumber">${h2Number}. </span>`);
                p.append(a);
                a.append(headingText);
                a.href = '#' + 'id2-' + h2Number;
                p.className = 'tableContent-h2';
                blogIndex.append(p);
                
                h2Number++;
                
                if (h3Number != 1) {
                    h3Number = 1;
                }
                
            } else if (tag == 'H3') {
                heading.id = 'id3-' + h3Id;
                let p = document.createElement('p');
                let a = document.createElement('a');
                p.insertAdjacentHTML('afterbegin', `<span class="indexNumber">${h3Number}. </span>`);
                p.append(a);
                a.append(headingText);
                a.href = '#' + 'id3-' + h3Id;
                p.className = 'tableContent-h3';
                blogIndex.append(p);
                h3Number++;
                h3Id++;
            }
        })
    //スムーススクロール
    // ページ内のリンクがクリックされたときに呼び出される関数
    function smoothScroll(target) {
        const element = document.querySelector(target);
        const elementPosition = element.getBoundingClientRect().top + window.pageYOffset - 50;
        // スクロール位置を計算して設定
        window.scrollTo({
            top: elementPosition,
            behavior: 'smooth'
        });
    }
    // リンクをクリックしたときの処理
    const links = document.querySelectorAll('.tableContent-h2 , .tableContent-h3');
    links.forEach((link) => {
        link.addEventListener('click', (event) => {
            event.preventDefault(); // リンクのデフォルト動作をキャンセル
            const target = link.querySelector('a').hash;
            smoothScroll(target);
        });
    })
});    

コードの説明

目次を挿入する用のHTMLを作成

//目次を設置する場所を作る
const articleContent = document.querySelector('.article-template__content');
articleContent.insertAdjacentHTML('afterbegin', `
    <div class="tableContent-wrapper">
        <div id="tableContent" class="tableContent">
            <div class="tableContent-title">
                目次
            </div>
        </div>
    </div> `
);

目次はコンテンツの前に設置したいのでコンテンツは

「insertAdjacentHTML」を使って設置しています。

直接コードを記事を書く際に管理画面から貼り付けてもいいのですが毎回面倒なのでJavaScriptを使って自動で設置しています。

 

h2とh3の要素を取得 

const headingArray = article.querySelectorAll('h2,h3');

 

「querySelectorAll」を使って要素を取得します

○ ('h2,h3')

×('h2','h3')

「' '」位置に注意です!私はここでつまづきましたw

 

取得した要素をもとに目次用のHTMLを生成

詳しい説明は省きますが

①h2.h3タグに個別のidを連番でつける

②目次用のHTMLを生成する

③はじめに生成した設置場所に目次用のHTMLを設置する

 

if文だったり条件分岐が入っていますが
①〜③の手順で下のコードを書いています。


headingArray.forEach((heading) => {
    let tag = heading.tagName;
    let headingText = heading.textContent;
    heading.className = 'blog-heading';
    if (tag == 'H2') {
        heading.id = 'id2-' + h2Number;
        let p = document.createElement('p');
        let a = document.createElement('a');
        p.insertAdjacentHTML('afterbegin', `<span class="indexNumber">${h2Number}. </span>`);
        p.append(a);
        a.append(headingText);
        a.href = '#' + 'id2-' + h2Number;
        p.className = 'tableContent-h2';
        blogIndex.append(p);
        
        h2Number++;
        
        if (h3Number != 1) {
            h3Number = 1;
        }
        
    } else if (tag == 'H3') {
        heading.id = 'id3-' + h3Id;
        let p = document.createElement('p');
        let a = document.createElement('a');
        p.insertAdjacentHTML('afterbegin', `<span class="indexNumber">${h3Number}. </span>`);
        p.append(a);
        a.append(headingText);
        a.href = '#' + 'id3-' + h3Id;
        p.className = 'tableContent-h3';
        blogIndex.append(p);
        h3Number++;
        h3Id++;
    }
})

スムーススクロールのコード

サイト内で遷移するときにスムーススクロールで動くようにコードを書いています。

//スムーススクロール
// ページ内のリンクがクリックされたときに呼び出される関数
function smoothScroll(target) {
    const element = document.querySelector(target);
    const elementPosition = element.getBoundingClientRect().top + window.pageYOffset - 50;
    // スクロール位置を計算して設定
    window.scrollTo({
        top: elementPosition,
        behavior: 'smooth'
    });
}
// リンクをクリックしたときの処理
const links = document.querySelectorAll('.tableContent-h2 , .tableContent-h3');
links.forEach((link) => {
    link.addEventListener('click', (event) => {
        event.preventDefault(); // リンクのデフォルト動作をキャンセル
        const target = link.querySelector('a').hash;
        smoothScroll(target);
    });
})

デフォルトだと画面の左上にリンク先が来てしまうので−50px上にずらしています

 

目次があるとブログは見やすい

やっぱり目次があるとブログは見やすいですね!

Shopifyでブログを書いていくにあたってまずは目次を作ろう!

と思ってたのでいい感じにできて満足です!

 

目次を実装したいけどうまくコードが書けないという方の参考になれば嬉しいです^^

ブログ一覧に戻る