みっちぇのWebデザイン研究所

はてなブログのカスタマイズを中心に、ウェブデザインについて研究するブログ

JavaScriptでDOM操作してみる

JavaScript勉強番外編。

本編(の前回の記事)はこっち micche-labo.hatenablog.com

アコーディオンメニューでよくある、クリックしたら開いて、クリックしたら閉じる、のような動きをJavaScriptで実装したらどうなるのか、ということを調べてみました。

まだ未完成なんですが、一旦やりたいことの第一歩は進んだ気がしたので記録。

できたのはこれ。

See the Pen クリックイベントでアコーディオンメニューその1 by Micche (@micche) on CodePen.

ひとつめの項目しかアコーディオンになってません。

とりあえずここまでのJavaScriptの挙動をメモ。

DOM操作-クリック、トグル

今回は

  • クリックで出てくる
  • もう一度クリックで隠れる

といった部分はCSSで実装し、JavaScriptには

  1. クリックしたら
  2. クラスのつけはずし

をしてもらいます。

HTMLとCSSで見た目を作り、整える

プログラムを書く前に、まずはHTMLとCSSのそれぞれの記述。

HTML

<ul class="accordion">
<li class="menu js-menu">アコーディオンメニュー
<ul class="child">
<li>子要素</li>
<li>子要素</li>
<li>子要素</li>
</ul>
</li>
<li class="menu js-menu">アコーディオンメニュー2
<ul class="child">
<li>子要素2</li>
<li>子要素2</li>
<li>子要素2</li>
</ul>
</li>
<li class="menu js-menu">アコーディオンメニュー3
<ul class="child">
<li>子要素3</li>
<li>子要素3</li>
<li>子要素3</li>
</ul>
</li>
</ul>

とりあえず三つアコーディオン作ります。

CSS

* {
margin: 0;
padding: 0;
}

body {
font-size: 16px;
letter-spacing: .05em;
}

/*ここからアコーディオンのスタイル*/

ul {
list-style: none;
}

.accordion {
display: flex;
flex-direction: column;
width: 100%;
}

.menu {
width: 100%;
background-color: pink;
text-align: center;
cursor: pointer;
line-height:2em;
transition:all .3s;
position:relative;
}

.menu:hover,
.menu:active,
.menu.is-active, 
.is-open li:hover{
background-color: palevioletred;
color: white;
}

/*はじめは非表示*/
.child {
text-align: center;
line-height: 0;
height: 0;
width:100%;
overflow: hidden;
opacity: 0;
transition: all .3s;
  
/*出てくる位置*/
position:absolute;
top:1.5em;
left:0;

/*出てくる要素を一番上に*/
z-index:999;
}

/*クラス付与されたら表示*/
.is-open{
line-height: 2em;
height: calc(2em * 3); /*3項目なので×3*/
color:#333;
opacity: 1;
top:2em; /*親要素の高さ分下げる*/
left:0;
}

.is-open li{
border-top:1px solid black;
background:pink;
transition:all .3s;
}

/*PC用アコーディオンメニュー横並び指定*/
@media screen and (min-width:760px) {
.accordion {
flex-direction: row;
}
}

CSSには、<li class="menu js-menu">につける用の.is-activeと、<ul class="child">につける用の.is-openを追加しておきます。

これで準備OK。

今の状態は多分こんな感じ。

f:id:micche-labo:20211002151259p:plain
今の状態

まだクリックしても何もおこりません。

JavaScript部分を書く

ではJavaScript部分を書いていきます。

順序は、

  1. 要素の取得
  2. 取得した要素でクリックイベントを作る
  3. クリックイベント内でタグのつけ外しを指示する

といった感じ。

1.要素の取得

今までJavaScriptの勉強で行ってきた、変数に格納ってやつをやっていいます。

初回のコレ micche-labo.hatenablog.com

const ul = document.querySelector('.js-menu'); //.js-menuの要素を取得
const li = document.querySelector('.child'); //.childの要素を取得

DOM操作についてはまだ全然勉強できてなんですが(そこ重要)、なんとかググってこうなりました。

それぞれ説明すると、

  1. document は、 html内を指します。

    f:id:micche-labo:20211002151911p:plain
    documentの部分

  2. querySelector()は、html内のセレクターを指します。()内にタグ・id・クラスを入れてあげることで、機能します。

    f:id:micche-labo:20211002153109p:plain
    document上のulを取得したい場合は、document.querySelector('ul');とする
    このとき、documentがないとエラーになるので注意。

  3. ()に取得したいidやclass、タグ名を''でくくって書く。 例:('#menu');('.child');('ul');など。

補足
documentには変数を入れることも可能。
const ulItem = document.querySelector('ul');で一旦ulを取得。
そのあと、ulItem.querySelector('.js-menu');ul内にあるjs-menuクラスのついた要素を取得している。

f:id:micche-labo:20211002154531p:plain
こんなパターンも

POINT
querySelectorはたくさん一致する要素がある場合、一番初めの要素のみを取得する
今回はひとつめのアコーディオンの要素のみ取得しているので、ほかのふたつは動かない挙動となっている。

ということで要素を取得できました。

注意

  • querySelector();のカッコ内は''でくくる。
  • classなら.idなら#を忘れずにつける。

2.クリックイベントをつくる

以下は関数を省略した形。

ul.addEventListener('click',() => {
//ここにトグルイベント実装
}

説明

addEventListener()内には、イベントの種類、関数、イベント伝搬の方式(trueかfalseか)が入ります。

例えば、

ul.addEventListener( 'click', toggleEvent, false );

のように書くことができる。

真ん中のtoggleEventは関数名。

なくてもOK。

例1

関数名を書いた場合の記述は、

ul.addEventListener( 'click',  toggleEvent, false );

function toggleEvent() {
//ここにイベントの処理
//例えば
ul.classList.toggle('is-active'); //is-activeというclassをつけ外し
}

のように、関数を分けて書くことができる。

例2

関数名を省いた場合。

ul.addEventListener('click', function() {
//ここにイベントの処理
}, false);

と書くか、もしくは今回採用した書き方のように、

ul.addEventListener('click', () => {
//ここにイベント処理
});

のように書く。(アロー関数使用。)

3.トグルイベントを作る

最後にトグルイベントを作成。

ul.classList.toggle('is-active');
li.classList.toggle('is-open'); //.js-menuクリックで.childに.is-openが付与

最初に定義した、ulliに格納した.js-menuクラスのついた要素と、.childクラスのついた要素に対して、クラスをつけ外しするような処理を書いています。

まとめ

まとめるとこう記述します。

//取得
const li = document.querySelector('.child'); //.childの要素を取得
const ul = document.querySelector('.js-menu'); //.js-menuの要素を取得
//クリックイベント。関数は省略。
ul.addEventListener('click',() => {
ul.classList.toggle('is-active');
li.classList.toggle('is-open'); //.js-menuクリックで.childに.is-openが付与
});

変数名に「li」やら「ul」したのは失敗だったな。
わかりづらい。

とりあえず第一歩ということで。

全部のアコーディオンを開閉できる日は来るのか…!

つづく。