Bloggerでページの目次をサイドバーに掲載
もともと美的センスやCSSの技術を持ち合わせない筆者にとって、HTMLページのレイアウトは簡単なものではなかったのですが、レスポンシブデザインが登場してからさらに難しくなりました。
幸いBloggerではサイドバーを簡単に作ることはできます。しかし今度はそこに配置するコンテンツに悩みます。
他でよく見るページではサイドバーのコンテンツは貼りついて動かないこともありますが、筆者はそれが何となく気持ち悪いです。
そこでサイドバーを埋めるコンテンツとして、ブログページの目次をJavaScriptで作ってみようというのが今回の記事です。
などと言いながら将来サイドバーのコンテンツを動かないようにしたりするかもしれませんが、その際はご容赦ください。
概要
HTMLビューでページを作成している前提で話を進めます。まず既存の「テーマ」のバックアップを取っておきます。「テーマ」から縦の...を選び「バックアップ」、「ダウンロード」で現在のレイアウトを保存しておきます。
大なり小なりレイアウトを修正することになります。おかしくなった時はこのバックアップを使って復元します。このバックアップはテーマだけで本文等は含まれないのに注意してください。
復元の仕方は「元に戻す」から「アップロード」と進み、ダウンロードしたバックアップファイルを選択します。
Bloggerのレイアウトマネージャーから処理するには「レイアウト」から対象のサイドバーで「+ガジェットを追加」ボタンを押し「HTML/JavaScript追加」を選びます。
レイアウトを直接編集する場合は「テーマ」→「HTMLの編集」から処理します。
サイドバーでページの目次を設置したい場所にdivタグをつくりidを設定します。ここでは「page-index」というidを設定しました。
JavaScriptでページから目次となる要素を取得して、作成したdivタグの中に目次をセットします。このJavaScriptはページが読み込まれた後に実行されるようにします。
JavaScriptのコーディング
筆者の場合はブログの本文にh3で見出しをつけていたので、この見出しを目次に使いたいと思います。またブログ記事外にあるh3タグと区別するためにブログ記事だけをclassで絞り込みます。デフォルトのBloggerだとpost-bodyとなっている箇所で、筆者はorg-post-bodyとリネームしています。
次のようなメソッドを使って対象を取得していきます。
- getElementsByTagName
タグ名でエレメントを取得します。戻り値はHTMLCollectionになります。WebKit(Apple系のレンダリングエンジン)だとNodeListになるそうです。
- getElementsByClassName
クラス名でエレメントを取得します。戻り値はHTMLCollectionになります。
- getElementById
getElementByIdで取得すれば戻り値はエレメントになります
ここではまずgetElementsByClassNameを使ってdiv(ブログ記事)を取得した後で、getElementsByTagNameを使ってh3(見出し)を取得しています。
divの取得では[0]を付けることで一番最初のエレメントを単体で取得しています。筆者のページ構成では指定したクラス名のエレメントは一つしかないことになっているので決め打ちしています。
取得したエレメントからh3タグを指定してさらに絞りこみます。
let elDiv = document.getElementsByClassName('org-post-body')[0];
let elH3 = elDiv.getElementsByTagName('h3');
新規にエレメントを作成して見出しを挿入します。見出しクリック時に該当の場所に移動するように、エレメントにさらにJavaScriptを設定しています。scrollIntoView(true)メソッドで呼び出したエレメントの位置に移動するのですが、筆者のページの場合はヘッダが60pxあるのでその分さらにscrollBy(x,y)で移動させています。
let elOl = document.createElement("ol");
for(let i = 0; i < elH3.length; i++) {
let elLi = document.createElement("li");
elLi.innerHTML=elH3[i].innerHTML;
elLi.onclick=function() {
elH3[i].scrollIntoView(true); scrollBy(0,-60);
};
elOl.appendChild(elLi);
}
作成したエレメントを先に作成しておいたdivの枠に当てはめます。
let elTarget = document.getElementById('page-index');
if(typeof elTarget !== "undefined") {
elTarget.appendChild(elOl);
}
これらのスクリプトを<script>タグ間に記述します。
テンプレートを直接編集するのならスクリプトはbodyタグが閉じられる前に記述するか、一連の処理を関数化しておいて、HTMLが表示し終わった後に実行してください。サイドバーを見つけて、表示場所となるdivタグを記入するのも忘れずに行います。
BloggerのHTML/JavaScriptガジェットからサイドバーに記述するなら<script>window.onload=(function(){...})();</script>として、無名関数の内側(...部)に記述して、HTMLページ読み込みの後にJavaScriptが実行されるようにします。表示場所となるdivタグはscriptの外にそのまま記述します。
テンプレートにJavaScriptを記述する場合for文で使用している<は<と記述しないとエラーとなり保存できません。これは<がHTMLタグの一部として認識されてしまうからです。
HTML/JavaScriptガジェットに記載する場合、プレビュー画面では対象のdivタグをうまく取得できずにエラーとなるようです。おそらくBloggerアプリの構造上の問題だと思います。コーディングに問題がなければ、実際のページでは意図したように表示されます。
あとは既存のページに適合するようにCSSを整えます。