wordpressで目次を実装
2018年01月3日
目次
wordpressで目次を実装
こんにちは。ウェブエンジニアのジワタネホです
今日はwordpressの記事に目次を実装する手順を備忘録として残します。
ちなみにプラグインなしで,jQueryで実装します。
サクッと実装したい方の参考になれば!!
背景
今回は、wordpressの目次実装です。
当初はプラグインでサーバー側で実装しようかと思ったのですが、
ざっとプラグインを見るとフロント側で完結しそうなロジックだったので、javascriptでやっちゃおうと。
そもそも僕ウェブエンジニアだったし。jqueryとか得意だし。
前提条件
実装前の条件としては以下になります。以下の条件が揃ってない場合は条件を揃えてから実装してください。
- 目次にする見出しのhtmlタグが全て統一されていること
- $を使えるようにしておく。面倒なので。わからない方は、「wordpress jQuery $」とかでググってください。
- アイコンとかはfontawesome使ってます。こちらもわからない方は、ググってください。
- とりあえずは、cssはPC版のみ。モバイルやタブレットは適宜宜しくです。
デモ
コード
html
<div class="single-page-index js-indexContent"> <div class="single-page-index-header js-indexHeader"> <h2 class="__index-h2">目次</h2> <span class="__toggle-btn"><i class="fa fa-angle-up __icon js-indexToggleBtn" aria-hidden="true"></i></span> <!-- /.single-page-index-header --></div> <div class="single-page-index-body js-indexBody"> <ul class="index-list js-indexList"></ul> <!-- /.single-page-index-body --></div> <!-- /.single-page-index --></div>
css
.single-page-index{ margin-top: 24px; border: 1px solid #aaa; border-radius: 8px; background-color: #fff; box-shadow: 0 0 5px rgba(0,0,0,0.5); } .single-page-index-header{ display:-webkit-box; display:-ms-flexbox; display: -webkit-flex; display:flex; border-top-left-radius: 5px; border-top-right-radius: 5px; border-bottom: 1px solid #aaa; background-color: #eee; padding: 0 16px; } .single-page-index-header .__index-h2{ font-size: 24px; line-height: 2; font-weight: bold; } .single-page-index-header .__toggle-btn{ margin-left: auto; font-size: 24px; line-height: 2; } .single-page-index-header .__icon{ cursor: pointer; } .single-page-index-header .__icon:hover{ opacity: 0.5; } .single-page-index-body{ padding: 16px; } .single-page-index .index-list{ padding: 0 8px; } .single-page-index .__item{ font-size: 16px; line-height: 2; } .single-page-index .__jump-btn{ color: #49b2d2; } .single-page-index .__jump-btn:hover{ opacity: 0.5; }
javascript
//ページのレンダリング時に実行 $(document).ready(function(){ //js-indexContentというタグがあった場合に目次を作る(=記事ページのみに作る) if($(".js-indexContent").length > 0){ //目次の見出しが二つ以上あった場合の処理 if($(".__h2").length > 1){ //目次の見出しを取得 $(".__h2").each(function(id){ var idName = "index_" + id; //目次になるテキストを取得 var indexTitle = $(this).text(); var addList = '<li class="__item"><a class="__jump-btn js-jumpBtn" href="#' + idName + '">' + indexTitle + ' </a></li>' $(this).attr("id", idName); //目次を追加 $(".js-indexList").append(addList) }); //目次をクリックした場合に該当箇所へスクロールさせる $(document).on("click", ".js-jumpBtn", function(e){ var speed = 400; var href= $(e.target).attr("href"); var targetHref = $(href == "#" || href == "" ? 'html' : href); var position = targetHref.offset().top; $("body,html").animate({scrollTop:position}, speed, 'swing'); return false; }); //目次のアコーディオン実装 $(".js-indexToggleBtn").on("click", function(){ //目次の開閉で表示出し分け if($(".js-indexBody").css("display") =="none"){ $(".js-indexBody").slideDown(); $(this).removeClass("fa-angle-down"); $(this).addClass("fa-angle-up"); $(".js-indexHeader").css("border-bottom-left-radius", "0"); $(".js-indexHeader").css("border-bottom-right-radius", "0"); }else{ $(".js-indexBody").slideUp(); $(this).removeClass("fa-angle-up"); $(this).addClass("fa-angle-down"); $(".js-indexHeader").css("border-bottom-left-radius", "5px"); $(".js-indexHeader").css("border-bottom-right-radius", "5px"); } }); }else{ //目次の項目が一つしかない場合は非表示へ $(".js-indexContent").hide(); }; }; });
解説
基本要件
- ページを読み込むタイミングで、目次のHTML要素を生成して表示する
- 目次の表示は記事ページのみに表示する
- 邪魔な場合もあるので、目次部分は開閉可能にする(=アコーディオンにする)
- せっかくなんで、見出しをクリックしたら該当箇所にウィーンってスクロールするようにする
ロジック
ざっとjavascriptの1行目から見ていきます。
HTMLに関しては、目次を常時させたいテンプレートファイルに追加してください。基本記事用のテンプレートファイルってことですね。
まず2、5行目の条件分岐
$(document).ready(function(){ if($(".js-indexContent").length > 0){ }; });
まず、ページの読み込み時にイベントの発火を設定します。
その後に目次用の要素があるのかないのかを判定します。
この判定はwordpressの記事用のテンプレートかを判断すれば良いので、サーバーサイドで最初から判定していても良いかもですね。
8〜19行目
$(".__h2").each(function(id){ var idName = "index_" + id; var indexTitle = $(this).text(); var addList = '<li class="__item"><a class="__jump-btn js-jumpBtn" href="#' + idName + '">' + indexTitle + ' </a></li>' $(this).attr("id", idName); $(".js-indexList").append(addList) });
目次に使うテキストを取得して、".js-indexList"の配下にHTMLとして追加していきます。
っていうのをページ内の"__h2"の数だけ繰り返します。
これで目次の基本は完成。
22〜29行目
$(document).on("click", ".js-jumpBtn", function(e){ var speed = 400; var href= $(e.target).attr("href"); var targetHref = $(href == "#" || href == "" ? 'html' : href); var position = targetHref.offset().top; $("body,html").animate({scrollTop:position}, speed, 'swing'); return false; });
生成した目次をクリックするとスクロールしてページ内リンクに移動するようにします。
ページ内のリンク先は12行目で既に設定済みなので、スクロールのアニメーションだけ実装します。
注意点としては、通常の目次の見出し要素のクリックイベントではなく、documentに対してのクリックイベントにして、引数に各見出しを設定していること
jQueryでは後から追加した要素に対して通常のクリックイベントは設定できません。
日本語でいうと、
×該当要素をクリックしたらスクロールする
○クリックした要素が該当要素だったらスクロールする
なんです。
29行目〜最後
$(".js-indexToggleBtn").on("click", function(){ //目次の開閉で表示出し分け if($(".js-indexBody").css("display") =="none"){ $(".js-indexBody").slideDown(); $(this).removeClass("fa-angle-down"); $(this).addClass("fa-angle-up"); $(".js-indexHeader").css("border-bottom-left-radius", "0"); $(".js-indexHeader").css("border-bottom-right-radius", "0"); }else{ $(".js-indexBody").slideUp(); $(this).removeClass("fa-angle-up"); $(this).addClass("fa-angle-down"); $(".js-indexHeader").css("border-bottom-left-radius", "5px"); $(".js-indexHeader").css("border-bottom-right-radius", "5px"); } });
ここはもう説明することなしw
ボタンをクリックしたら、閉じたり開けたりするやつ
最後に
とりあえず簡単に実装しました。
まあ今回は必要ないのだけど、この実装だと、見出しは作れても小見出しとかが作れないのが残念。
ご指摘やご意見お待ちしております!
※1月8日追記
目次の項目が一つだった場合に、目次とか表示する意味がないので、その場合は非表示にする処理を追記しました。
javascriptの8行目と50〜52行目です。
if($(".__h2").length > 1){ //目次生成処理 }else{ $(".js-indexContent").hide(); };