JavaScriptをいじり始めてまだ初級者の自分。コードの記述に慣れてくると、色々と面倒な部分も見えてきました。document.getElementById('id')
とか、 var.addEventListenner('click')
とか、 createElement('p')
とか…DOM操作が長くてなんか苦手なんですよね…
聞くところによると、そんな苦手なDOM操作を手軽に記述で出来るモノがあるらしい。「ライブラリ」。今まで何となく聞いたことはある。有名どころではjQueryとかReactとかかな?特にjQueryがDOM操作に長けているらしい。
でも個人で使うのにもう少し軽量なものでもいい気がする。そこで見つけたのが「Umbrella JS」。jQuery派生でDOM操作が得意で、見た目にもjQueryよりスッキリしてる感じ。例えばセレクターの指定では、
- jQuery $(“div”)
- Umbrella JS u(“div”)
このように、$とuに違いがあるんですが、$だと、バックティック“ 利用時の${var}と間違えやすそう だし、u()の方が小文字の分、カッコよりも高さが半分なのが視認しやすそう な感じがしました。まあ、あくまで個人の感想なんですけどね…
ということで今回は、ライブラリをまだ1回も使った事が無い(笑)自分が練習がてら、Umbrella JSを使い、目次を作ってみようと思います!
Umbrella JSの設置方法
ライブラリの使い方には、以下の方法があるようです。
- ダウンロード ファイルをDLし、htmlと同じサーバーに設置する方法
- CDN htmlにURLを記述し、ネット経由で毎回読み込みに行く方法
- npm Node.js環境で管理ツールで管理する方法?(よくわからん)
…ま、とりあえずCDNがお手軽でよさそうですね。調べてみると、Umbrella JS もCDNを使える様子。早速「Umbrella JS の公式ページ」へ飛んでみます。そしてライブラリをCDNで設置する方法はというと、
<script src="https://cdn.jsdelivr.net/npm/umbrellajs"></script>
↑のコードをhtmlの何処かに貼り付ければいいだけ。すごい、簡単ですね。
ただ、このURLが途中で変わってしまうようだと困りものではあるんですよね。ま、そんな頻繁に変わる事は無いと思うけど…
目次作成にあたって
ただ何もない所からは中々最終形が見えてきませんので、今回の目次製作には、こちらのサイトを参考にさせていただきました!
そして、公式ページの内容を和訳してくれてるサイトです。助かります!
そして目次を設置する前の、生html は、こちらになります!
<body> <script src="https://cdn.jsdelivr.net/npm/umbrellajs"></script> <h2>目次@umbrellajs</h2> <h3>h3見出し01</h3> <div> …h3見出し01文章 </div> <h4>h4見出し01</h4> <div> …h4見出し01文章 </div> <h4>h4見出し02</h4> <div> …h4見出し02文章 </div> <h3>h3見出し02</h3> <div> …h3見出し02文章 </div> <h4>h4見出し03</h4> <div> …h4見出し03文章 </div> <h4>h4見出し04(h3見出し02)</h4> <div> …h4見出し04文章1<br> …h4見出し04文章2<br> …h4見出し04文章3<br> …h4見出し04文章4<br> …h4見出し04文章5<br> …h4見出し04文章6<br> …h4見出し04文章7<br> …h4見出し04文章8<br> …h4見出し04文章9<br> …h4見出し04文章10<br> …h4見出し04文章11<br> </div> <script> /*---Umbrella JS ---*/ </script> </body>
スクリプト自体は、上記htmlの下方 <script></script> の間にUmbrella JSメインで記述していきます。そしてやりたいことは、
- <h2> 見出し下に、目次を設置
- 見出しタグ(h3、h4)を元にアンカーリンク付き
- <details>と<summary>で、アコーディオン化
- 目次にはCSSを充てる用のclassを設定
目次試作品
そして急ですが(笑)、試作品のコードは以下になります。
<script> /*---Umbrella JS ---*/ /*---目次設置 ---*/ u("h2").after('<details id="contents" open><summary>Sample-of-Contents'); u("#contents").append('<ul id="lists">'); u("h3, h4").each((e, i) => { u("#lists").append(`<li class="${e.localName}_category"><a href="#list_${i}">${u(e).text()}`); u(e).attr({id: `list_${i}`}); }) </script>
とりあえず、6行程度のコードで目次が完成しまいた。
.after()、.append()
目的の個所に、htmlの要素を挿入していきます。手順としては非常に簡単で、
u("div")
などでhtml 上の該当セレクターを指定する- セレクターの後に.append(“タグ要素”)などで設置したいタグを指定する
セレクター指定は、u("div")
のようなタグの指定から、u("#id")
やu("p.class")
などのidやclassの指定、u("ol > li")
子要素指定、u("h3, h4")
などカンマで区切って複数指定など一連のセレクター指定が出来るようです。 document.getElementById('id')
で指定して変数に入れて…とか少し長くて見にくかったセレクター指定がu(“div”)こんな簡素に出来るとか、非常に見やすいですね。
要素の挿入は、.after()
、.before()
、.append()
、.prepend()
などで行います。この4つはvanilla でも見覚えのあるものなので、使いやすいと思います。ただ面白いのは、 u("div")
と開始タグのみの指定でも<div></div>
と終了タグ付きで挿入してくれる点ですね。
/*開始タグのみの指定だけど… */ u("ol").prepennd("<li><a>こんにちは") /*終了タグ付きで設置してくれる!*/ <li><a>こんにちは</a></li>
そんな事を踏まえ、要素の挿入をしていくと、
/*<h2> の見出しの下に、この様な形で要素を設置したい時に…*/ <details id="contents" open> <summary>Sample-of-Contents</summary> </details> /*例1、追加要素を1列で一気に入れてしまう方法*/ u("h2").after('<details id="contents" open><summary>Sample-of-Contents'); /*例2、セレクターを分け、タグ要素ずつ分割で挿入する方法*/ u("h2").after('<details id="contents" open>'); u("#contents").append('<summary>Sample-of-Contents'); /*例3、失敗例、元々の選択セレクタの方にidやtextが入ってしまう!*/ u("h2").after('<details open>').attr({id: 'contents'}); u("contents").append('<summary>').text('Sample-of-Contents');
こんな感じになります。例2の分割して挿入もスッキリ見やすいので、好みで使い分けてもよさそうです。例3は失敗例です。idやtextやclassの後挿入の狙いでしたが上手くいかず、元々の選択セレクタの方に入ってしまいます。設置済みのタグ要素であれば、そこをセレクタで指定して、idやtextやclassの後挿入も出来るかと思います。
それから.after()
、.append()
などには、()内に関数を利用した使い方もあるようです。
/*配列内の各要素を順番に処理する*/ .append(各要素 => {`<li><a>${各要素}`}, 配列) /*ul の子要素で、配列内の要素がappendで追加されていく*/ u("ul").append(el => {`<li>${el}`, ['おはよう', 'こんにちは', 'さようなら']); /*---配列内の各要素が<ul>の子要素として<li>タグで追加されていく*/
こちらはまだ研究中でして、また使いどころを模索しているところです。
.text()
- 取得
u("h2").text()
- 変更
u("h2")
.text('変更文字列') - 無文字
u("h2").text('')
- 付足し
u("h2").text(u("h2").text() + '付足し文字列')
textContent と同等の使い方かなと思います。便利なのですが、文字列の付足しだけはちょっと面倒くさい感じがあるかな?もう少しうまいやり方があればいいのですが…
.html()、.wrap()
.html()
は、innerHTML と同等な感じかな?基本的な使い方は、.text()
と同等と思われます。イメージ的には、セレクタの内側にタグを張る感じ(反対にセレクタの外側からラップするのが.wrap()
らしい?)つまり、こんな感じの例2の分割して挿入に関しては、以下のコードの様になるかと思います。
/*---<h2>以下を設置する時、全て同じ結果になる(ハズ)) ---*/ <h2>見出し</h2> <details> <summary>目次</summary> </details> /*---------------------------------------------------------*/ /*---.append() ---*/ u("h2").after('<details>'); u("#contents").append('<summary>目次'); /*---.html() ---*/ u("h2").after('<details>'); u("#contents").html('<summary>目次'); /*---.wrap() ---*/ u("h2").after('<summary>目次'); u("summary").wrap('<details>');
.attr()、.addClass()、.removeClass()
.attr()
は、id、class、href、他、タグ要素内の属性をいじれます。
- 属性の値の取得 .attr(‘属性名’)
- 属性と値の設置 .attr({属性名:’値’})
- 属性の値の空白 .attr({属性名:”})
- 複数設置 .attr({属性名1:’値’, 属性名2:’値’})
- スタイルに複数値 .attr({style: ‘値1; 値2’})
- 複数のクラス設置 .addClass(‘クラス名1′,’クラス名2’)
- 対象のクラスのみ削除 .removeClass(‘クラス名2’)
正直、属性を色々いじれる.attr()は、とても楽チンです.
ですが、クラスを複数取り扱う時は、クラス専用の.addClass()
や.removeClass()
を使う感じですね。
.each()
配列内の要素やインデックスを元に、順番に処理をしていきます。さしずめUmbrella JS版の forEach()
と言ったところでしょうか?使い方もほぼ同じです。1つ気に入った箇所を言えば、要素とインデックスの位置が、jQueryとは逆で、 vanillaのforEach()
と同じの位置関係になっている、これはいい(笑)
目次作成では、u("h3, h4")
で該当する複数の見出し要素を元に、アンカーリンク付きの目次と、元々の見出し自体にリンク用のid を設置を行っています。
/*アンカーリンク付きの目次作成と、元々の見出しh3h4に、リンク用id を設置する*/ u("h3, h4").each((e, i) => { u("#lists").append(`<li class="${e.localName}_category"><a href="#list_${i}">${u(e).text()}`); u(e).attr({id: `list_${i}`}); })
とりあえずの工夫点としては、<li>内にCSSを充てる用のclassを設けている点でしょうか?
具体的には、「.each()
で現在処理中の要素は、セレクターで言う所のh3h4 のどれになるのか?」の取得を「localName」で行い、「h3_category」or「h4_category」といったclass 名を作成しています。localNameは関数内で勝手に取得するので、仮にセレクターu(“h3, h4”)からu(“h2, h3, h4, h5, h6”)と増やしても、「h2_category」「h5_category」「h6_category」も<li> タグ内にclass名として自動で勝手に作成されます。便利ですね~(笑)
その他、今回ではまだよくわからなくて使ってないんですが、リストを列挙していくだけの方法として、次のようなやり方もあります。
/*.append()で関数を使って配列内の要素を列挙する方法*/ u("#lists").append((el, i) => `<li><a>${el}`,u("h3, h4").array());
上記でも挙げた、.append()で関数を使って配列内の要素を列挙する方法です。配列内の各要素やインデックスも取れるので、それなりの列挙も出来そうです。ただ.each()
と比べて上手く行かない点は、
- 複数の処理において、要素とインデックスの連動性のある処理が出来ない?
- 要素、インデックスは取れるが、localNameの取得方法が分からない?
要するに、アンカーリンク用の「`#list_${i}`」とリンク先のid
「`list_${i}`
」に連動性を持たせる必要があるため、同じ要素、インデックスで複数の処理が出来る.each()
に分があるのではないか?という事です。もちろん、そういった事が必要なければ、「.append()
& 関数 」でも良いと思います。
っていうか、後ろにある.array()
の()内を使って、上手く処理できないかな?要研究です。
.on()、.scroll() 戻るボタン設置
ついでなので、タイトル部(今回はh2)への戻るボタンも設置してみました。
/*---戻るボタン設置 ---*/ u("div").after('<button class="go_h2">戻る'); u(".go_h2").on('click',() => { u("h2").scroll(); });
簡単に説明しますと、
- 文章の入っているすべての<div>タグの下に戻るボタンを設置
.on('click', func)
でclickイベントを待機- func に関数で
.scroll()
設置、 h2へスクロール
少し面倒に感じていた addEventListener()
や createElement()
が結構シンプルに書ける気がします。便利です!(笑)
イベントを待機する .on()
に関しては、jQueryとは少し違う書き方のようです。でも大概は同じような感じなので、見て感覚で扱えるのではないでしょうか?
.toggleClass()、目次の表示切り替え
本当は無くてもいいんですが、おまけで目次の表示と非表示の切り替えを作ってみました。
/*---<h2>をクリックすると、目次の表示と非表示が切り替わる ---*/ /*---.toggleClass() CSS利用---*/ u("h2").on('click',() => { u("#contents").toggleClass('disNone',''); }) /*---.attr() でstyle変更 ---*/ u("h2").on('click',() => { if (u("#contents").attr('style') === 'display:none') { u("#contents").attr({style: ''}) } else { u("#contents").attr({style: 'display:none'}) }; }) /*---.attr() でstyle変更、正規表現、三項演算子 ---*/ u("h2").on('click',() => { /none/.test(u("#contents").attr('style')) ? u("#contents").attr({style: ''}): u("#contents").attr({style: 'display:none'}) })
Umbrella JSは、クラス系メソッドが、.addClass()
、.toggleClass()
、.hasClass()
、.removeClass()
と豊富に用意されていますね。DOM関連は、CSSとclassでいじるのが推奨という事なのでしょう。
まとめ
Umbrella JS、なんだかんだで、非常に使いやすいです。しばらく使って見ようかな?と思います。
最後に、今回のコードの最終形を載せておきます。
- html
<body> <script src="https://cdn.jsdelivr.net/npm/umbrellajs"></script> <h2>目次@umbrellajs</h2> <h3>h3見出し01</h3> <div> …h3見出し01文章 </div> <h4>h4見出し01</h4> <div> …h4見出し01文章 </div> <h4>h4見出し02</h4> <div> …h4見出し02文章 </div> <h3>h3見出し02</h3> <div> …h3見出し02文章 </div> <h4>h4見出し03</h4> <div> …h4見出し03文章 </div> <h4>h4見出し04(h3見出し02)</h4> <div> …h4見出し04文章1<br> …h4見出し04文章2<br> …h4見出し04文章3<br> …h4見出し04文章4<br> …h4見出し04文章5<br> …h4見出し04文章6<br> …h4見出し04文章7<br> …h4見出し04文章8<br> …h4見出し04文章9<br> …h4見出し04文章10<br> …h4見出し04文章11<br> </div> <script> /*---Umbrella JS ---*/ </script> </body>
- html内 <script></script>
<script> /*---Umbrella JS ---*/ /*---目次設置 ---*/ u("h2").after('<details id="contents" open>'); u("#contents").append('<summary>Sample-of-Contents'); u("#contents").append('<ul id="lists">'); u("h3, h4").each((e, i) => { u("#lists").append(`<li class="${e.localName}_c"><a href="#list_${i}">${u(e).text()}`); u(e).attr({id: `list_${i}`}); }) /*---戻るボタン設置 ---*/ u("div").after('<button class="go_h2">戻る'); u(".go_h2").on('click', () => { u("h2").scroll(); }) /*---<h2>クリックで目次の表示、非表示切り替え ---*/ u("h2").on('click',() => { u("#contents").toggleClass('disNone',''); }) </script>
- CSS
#contents { background-color: #CDFDEA; } li { list-style: none; } .h3_c { margin-left: 0px; } .h4_c { margin-left: 20px; } .disNone { display: none; }
コメント