WordPressのようなエディタで、ヘッダータグ(h1〜h6)とその中の要素をグループ化しようと思うと、HTMLタグで書く必要があったりと、なかなか不便なケースがあります。
この記事では、そんなヘッダー間の要素を自動的にグループ化するJavaScriptのコードを解説していきます。
このコードはカスタマイズもしやすいので、是非参考にしてみてください。
目次
.insertBefore()
JavaScriptの .insertBefore()
は、特定の参照ノードの直前に新しいノードを挿入するために使用されるメソッドです。このメソッドは親ノードに対して呼び出し、新しいノードと参照ノードを引数として取ります。
例えば、次のようなHTMLがあるとします。
<div id="parent">
<div id="child1"></div>
<div id="child2"></div>
</div>
ここで、「child1」の直前に新しいdiv要素を挿入したい場合、以下のようにinsertBefore()
を使用します。
var parent = document.getElementById('parent');
var newElement = document.createElement('div');
var referenceElement = document.getElementById('child1');
parent.insertBefore(newElement, referenceElement);
これにより、新しいdiv要素が”child1″の直前、つまり”parent”の最初の子要素として挿入されます。
今回はこのメソッドを使って div
タグで括ります。
h3タグ間の要素をdivタグで括ったサンプル
早速サンプルです。
見た目だけだと div
タグで括られているかがわかりづらいので、div
タグで括られている箇所の背景はグレーで記載しています。
サンプルのh3見出し1
サンプルの文章。サンプルの文章。サンプルの文章。サンプルの文章。サンプルの文章。サンプルの文章。
サンプルのh4見出し1
サンプルの文章。サンプルの文章。サンプルの文章。サンプルの文章。
サンプルの文章。サンプルの文章。
サンプルのh3見出し2
サンプルの文章。サンプルの文章。サンプルの文章。サンプルの文章。サンプルの文章。サンプルの文章。
サンプルの文章。サンプルの文章。サンプルの文章。サンプルの文章。
サンプルの文章。サンプルの文章。
サンプルのh3見出し3
サンプルの文章。サンプルの文章。サンプルの文章。サンプルの文章。サンプルの文章。サンプルの文章。
HTMLをデベロッパーツールで見てみると、「group」のclass名で div
タグで括られていると思います。
サンプルのHTMLソース
上記の表示サンプルのHTMLソースは、以下のように「group」のclass名で div
タグがない構造です。
<h3>サンプルのh3見出し1</h3>
<p>サンプルの文章。サンプルの文章。サンプルの文章。サンプルの文章。サンプルの文章。サンプルの文章。</p>
<h4>サンプルのh4見出し1</h4>
<p>サンプルの文章。サンプルの文章。サンプルの文章。サンプルの文章。<br>サンプルの文章。サンプルの文章。</p>
<h3>サンプルのh3見出し2</h3>
<p>サンプルの文章。サンプルの文章。サンプルの文章。サンプルの文章。サンプルの文章。サンプルの文章。</p>
<p>サンプルの文章。サンプルの文章。サンプルの文章。サンプルの文章。<br>サンプルの文章。サンプルの文章。</p>
<h3>サンプルのh3見出し3</h3>
<p>サンプルの文章。サンプルの文章。サンプルの文章。サンプルの文章。サンプルの文章。サンプルの文章。</p>
このHTMLのような h
タグと p
タグが並列階層になっているものを、JavaScriptで p
タグを div
タグで括られるようにしていくのがこの記事の内容です。
実装の手順と方法
コードの詳細の前に、実装の手順と方法について解説していきます。
JavaScriptのコードを記述します。
コードは <body>〜</body>
で、</body>
の閉じタグ(クロージングタグ)の前に記述しましょう。
// DOMの読み込みが完了したら処理を開始
document.addEventListener('DOMContentLoaded', function() {
// '.entry-content' クラスの子要素である全てのヘッダータグを取得
var headers = document.querySelectorAll('.entry-content > :is(h1, h2, h3, h4, h5, h6)');
// 取得した各ヘッダータグについて処理
headers.forEach(function(header) {
// ヘッダータグ名を小文字で取得
var h_tag = header.nodeName.toLowerCase();
// ヘッダーの次の要素を取得
var nextElement = header.nextElementSibling;
// 'group' クラスを持つ div 要素を新規作成
var group = document.createElement('div');
group.classList.add('group');
// 次の要素が存在し、ヘッダータグと異なる場合はループ
while (nextElement && nextElement.nodeName.toLowerCase() !== h_tag) {
// 現在の次の要素の次の要素を一時的に保存
var next = nextElement.nextElementSibling;
// 次の要素を 'group' に追加(移動)
group.appendChild(nextElement);
// 保存しておいた次の要素がヘッダータグと同じであればループを抜ける
if (next && next.nodeName.toLowerCase() === h_tag) {
break;
}
// 保存しておいた次の要素が存在しない、もしくはヘッダータグであればループを抜ける
else if (!next || next.matches(':is(h1, h2, h3, h4, h5, h6)')) {
break;
}
// 次の要素を更新
nextElement = next;
}
// 'group' に要素が存在する場合のみ、ヘッダーの次に挿入
if (group.children.length > 0) {
header.parentNode.insertBefore(group, header.nextSibling);
}
});
});
これだけでOKです。
ざっくりとしたコードの解説
コードは、JavaScriptのみです。ざっくりですが、解説します。
JavaScript
JavaScriptコードは、DOM(ドキュメントオブジェクトモデル)の一部であるヘッダータグ(h1〜h6)を操作して、ヘッダー間のコンテンツをグループ化し、それらを新しいdiv要素で括ります。
サンプルのコードでは .entry-content
クラスの子要素として存在するヘッダータグに対して動作します。
// DOMの読み込みが完了したら処理を開始
document.addEventListener('DOMContentLoaded', function() {
// '.entry-content' クラスの子要素である全てのヘッダータグを取得
var headers = document.querySelectorAll('.entry-content > :is(h1, h2, h3, h4, h5, h6)');
// 取得した各ヘッダータグについて処理
headers.forEach(function(header) {
// ヘッダータグ名を小文字で取得
var h_tag = header.nodeName.toLowerCase();
// ヘッダーの次の要素を取得
var nextElement = header.nextElementSibling;
// 'group' クラスを持つ div 要素を新規作成
var group = document.createElement('div');
group.classList.add('group');
// 次の要素が存在し、ヘッダータグと異なる場合はループ
while (nextElement && nextElement.nodeName.toLowerCase() !== h_tag) {
// 現在の次の要素の次の要素を一時的に保存
var next = nextElement.nextElementSibling;
// 次の要素を 'group' に追加(移動)
group.appendChild(nextElement);
// 保存しておいた次の要素がヘッダータグと同じであればループを抜ける
if (next && next.nodeName.toLowerCase() === h_tag) {
break;
}
// 保存しておいた次の要素が存在しない、もしくはヘッダータグであればループを抜ける
else if (!next || next.matches(':is(h1, h2, h3, h4, h5, h6)')) {
break;
}
// 次の要素を更新
nextElement = next;
}
// 'group' に要素が存在する場合のみ、ヘッダーの次に挿入
if (group.children.length > 0) {
header.parentNode.insertBefore(group, header.nextSibling);
}
});
});
コードはまず、.entry-content
クラスの子要素である全てのヘッダータグを取得します。
取得した各ヘッダータグについて、その次の要素から次の同レベルのヘッダータグまでの要素を新規に作成したdiv要素(group
)に追加します。その後、この新しいdiv要素を元のヘッダータグの直後に挿入します。
このコードは、.entry-content
の部分を他のセレクタに書き換えることで、異なるDOM要素に対しても同じ操作を行うことが可能です。つまり、ヘッダータグを取得する対象となるDOM要素を変更したい場合、.entry-content
をその新しいセレクタに置き換えればOKです。
カスタマイズも容易なので、コメントアウトを参考にして使ってみてください。
さいごに
今回は、hタグ間の要素をdivタグで括る(囲む)コードについての解説でした。
コードもJavaScriptのみでOKなので、HTMLを描くのが面倒な時など活用してみてください。