【Umbrella JS】で目次を製作。jQuery派生のJavaScriptライブラリの使い勝手は?

黒い傘の画像 JavaScript
フリーイラスト:pixabay

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が途中で変わってしまうようだと困りものではあるんですよね。ま、そんな頻繁に変わる事は無いと思うけど…

目次作成にあたって

ただ何もない所からは中々最終形が見えてきませんので、今回の目次製作には、こちらのサイトを参考にさせていただきました!

そして、公式ページの内容を和訳してくれてるサイトです。助かります!

Umbrella – にほんご。

そして目次を設置する前の、生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の要素を挿入していきます。手順としては非常に簡単で、

  1. u("div")などでhtml 上の該当セレクターを指定する
  2. セレクターの後に.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() と比べて上手く行かない点は、

  1. 複数の処理において、要素とインデックスの連動性のある処理が出来ない?
  2. 要素、インデックスは取れるが、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();
	});

簡単に説明しますと、

  1. 文章の入っているすべての<div>タグの下に戻るボタンを設置
  2. .on('click', func) でclickイベントを待機
  3. 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;
}

コメント

タイトルとURLをコピーしました