MENU

記事やブログで目次をクリックしたらスクロールしてくれるやつ、便利ですよね。このような目次を実装したい時、どうしてますか?

WordPressでは便利なプラグインがいくつかあるみたいですが、実はリンク付きで目次を自動生成するスクリプトは結構簡単に自作できちゃいます。

ほとんどコピペで実装できると思うので、プラグイン使うのは嫌だな〜って方は是非参考にしてみてください。

↓の目次もこの方法を応用して作成しています。

目次

手順1:記事内の見出しに使うhタグは統一し、区別可能にしておく

まずは準備です。今回の方法ではJavaScriptで見出しを探し出して目次を生成するので、見出しに使うhタグは統一させておきます。

ちなみに私の方法はというと、カスタムフィールドで章ごとの見出しと本文と作成し、見出しは全てh2タグで出力するように記述しています。

このとき、h2タグを見出し以外にも使用している場合は、見出しだけを探してこれるように配慮しておかなければなりません。

見出しに共通のクラスを付けておくか、記事の内容を表示させる領域をidやclass付きのdivで囲っておくなどしておきましょう。

手順2:目次を表示させたい場所にulタグを置いておく。

もう一つだけ準備をしておきます。single.php内で目次を表示させたい場所を決め、そこに id付きのulタグを置いておきます。

中身は空でOKです。

<!--  目次を表示させたい場所   -->
<ul id="index"></ul>

ここに、後から自動生成したリストを移動させてきます。

手順3:each()メソッドで見出しごとにliタグを作成していく。

ここからJavaScriptの内容に入っていきます。

jQueryのeach()メソッドを利用して、各見出しのテキストを取得し、リンク先の目印となるようにidを付与していきます。

私は"post_content"というdivの中に投稿内容を表示させているので、ソースは以下のようになります。

var indexNum = 1;  //付与するid用変数
var indexHtml = "";   //最終的にulタグに移動させるhtmlソース

//ここから見出しごとのループ処理
var $h2 = $('.post_content h2');
if($h2.length > 0){
  $h2.each(function(){
    var indexId = "indexId"+indexNum; //id作成
    var text = $(this).attr('id', indexId).text();   //id付与しつつ、見出しテキスト取得
    indexHtml += '<li><a href="#'+indexId+'">'+text+'</a></li>';
    indexNum++;
  });
}

見出しを見つけるごとに、9行目でidを付与しつつ見出しのテキストを取得して、10行目で付与したidをhref属性持つaタグを含んだliタグを作成しています。

index_html = '<li><a href="見出しにつけたid">見出しの内容テキスト</a></li>'+'...';

というhtmlが連結していったものが、あらかじめ定義してある indexHtml の中に代入されていきます。

手順4:作成したliタグをappend()でulタグに移動させる

先ほど作成したindexHtmlをあらかじめ準備しておいたulタグ(id="index")の中へ移動させて、動作は完成です。

ulタグへの移動はappend()またはprepend()メソッドを使用します。

$('#index').append(index_html);

ここまでで、記事内の見出しからリンク付きの目次を自動生成するスクリプトは作成できます。

 

仕上げ:投稿ページのみ・見出しがある場合のみ動作させる。

最後に、投稿ページ以外で動作するとエラーになるので、目次用のulタグがある時だけ動作するようにしておきます。

また、ブログの内容が短くてh2タグがない場合などは空の見出しが生成されてしまうので、if分でそのような場合の条件分岐もしていきます。

以上をまとめると、以下のようになります。

//投稿ページなら(#indexがあれば)
if(document.getElementById("index") !== null){
  var index_num = 1;     //付与するid用変数
  var index_html = "";   //最終的にulタグに移動させるもの

  //ここから見出しごとのループ処理
  var $h2 = $('.post_content h2');
  if($h2.length > 0){
    $('.post_content h3').each(function(){
      var index_id = "index_id"+index_num,
          text = $(this).attr('id', index_id).text();
      index_html += '<li><a href="#'+index_id+'">'+text+'</a></li>';
      index_num++;
    });
    $('#index').append(index_html);
  }else{
    //見出しがない場合は目次用ulタグを隠す
    $('#index').hide();
  }
}

見た目などはCSSで好きにアレンジしていってください!

おまけ:リンク先への移動をアニメーションさせる

おまけです。特に何もしなければ、リンク先への移動は瞬間移動してしまいますが、これをアニメーションさせるとさらにいい感じになります。

 $('a[href^="#"]').click(function(){
  var speed = 800, //スピード
      href = $(this).attr("href"),
      target = $(href === "#" || href === "" ? 'html' : href),
       position = target.offset().top; //スクロールさせる位置
   $("html, body").animate({scrollTop:position}, speed, "swing");
   return false; //忘れずに
});

このスクリプトの中身については前回のメモ:[href^=#]とはなんぞやでも触れているので、気になった方は調べてみてください。

return false;を記述し忘れると、アンカータグ本来の挙動とバッティングして動作がカクつくようにバグってしまうので、忘れないように注意してください。

また、ヘッダーをdisplay: fixed で固定している場合は、ヘッダーが見出しに被ってきてしまうと思います。

もしそのような場合は、ヘッダーの高さを取得し、その高さ分だけスクロールさせる位置をずらしてあげることで改善できます。

header全体を固定させている場合は、

var head_height = $('header').outerHeight();

で固定部分の高さを取得できます。

自分のページで固定させている要素の高さをoutherHeightで取得し、上記スクリプトのpositionの数値から引いてあげましょう。

まとめ

以上、プラグインを使わずに記事内の見出しからリンク付きの目次を自動生成させる方法と、目次をクリックした時のリンクの移動をスムーススクロールのアニメーション付きで実装する方法でした。

 

- Thank you for reading this to the end. -
TOPへ Top