Skip to content

Commit

Permalink
「素のJavaScript + DOM入門」を 2024年度bootcampに向けて加筆・修正 (#179)
Browse files Browse the repository at this point in the history
* 「DOM」に関して細かい表現の修正

* DOMの講義のまとめにおける、`addEventListener`についての説明をわかりやすく

* JavaScriptで要素の属性を設定する節を追加

去年時間が余り気味だったので内容を足しました
  • Loading branch information
igrep authored Aug 19, 2024
1 parent f27a7d1 commit daf3965
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 5 deletions.
Binary file added src/frontend/dom/7-buttons.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/frontend/dom/7-frame-button.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 46 additions & 0 deletions src/frontend/dom/7.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script type="module">
const postContentsInput = document.getElementById("postContents");
const doPostButton = document.getElementById("doPost");
doPostButton.addEventListener("click", (event) => {
const postContents = postContentsInput.value;
const p = document.createElement("p");

const deleteButton = document.createElement("button");
const deleteButtonText = document.createTextNode("X");
deleteButton.appendChild(deleteButtonText);
deleteButton.addEventListener("click", () => {
document.body.removeChild(p);
});
p.appendChild(deleteButton);

const flameButton = document.createElement("button");
const flameButtonText = document.createTextNode("🔥");
flameButton.appendChild(flameButtonText);
flameButton.addEventListener("click", () => {
p.setAttribute(
"style",
`
color: red;
font-size: 200%;
font-weight: bold;
`
);
});
p.appendChild(flameButton);

const text = document.createTextNode(postContents);
p.appendChild(text);
document.body.appendChild(p);
});
</script>
<title></title>
</head>
<body>
<input id="postContents" type="text" placeholder="いまどうしてる?">
<button id="doPost">投稿する</button>
</body>
</html>
77 changes: 72 additions & 5 deletions src/frontend/dom/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,7 @@ console.log(f("あれ、一つ目しかない!"));

#### 関数式(⚠️重要⚠️ 後ほど使用します)

JavaScriptの世界では、これまで紹介した文字列や数値、配列などと同様に、関数も変数に代入したり、他の関数の引数として渡したりすることができるようになっています(このことを「JavaScriptでは、関数もファーストクラスオブジェクトである」と言います)。これはこの後紹介するイベントリスナーを実現するためにも使われている、大変重要な機能です。
JavaScriptの世界では、これまで紹介した文字列や数値、配列などと同様に、**関数も変数に代入したり、他の関数の引数として渡したりする**ことができるようになっています(このことを「JavaScriptでは、関数もファーストクラスオブジェクトである」と言います)。これはこの後紹介するイベントリスナーを実現するためにも使われている、大変重要な機能です。

関数を「他の関数の引数として渡す」のを円滑に行うために、名前の付いていない関数を定義する「関数式」という構文があります。

Expand Down Expand Up @@ -586,10 +586,10 @@ functionReceivingAnotherFunction(f2);

## DOMツリーをたどる

これから、JavaScriptでHTMLの内容を編集する方法を一つずつ紹介します。HTMLで書かれた文書をJavaScriptで操作するとき、文書の内容は「DOM (Document Object Model)」と呼ばれる形式のデータを操作することになります。「DOM」という言葉自体の定義はちょっと抽象的で分かりづらいので、ひとまずここでは、今後「DOMオブジェクト」とか「DOMツリー」といった言葉を見た時「あっ、JavaScriptでHTMLの内容を操作する話をしてるんだな」と思えるようになれればよいでしょう。
これから、JavaScriptでHTMLの内容を編集する方法を一つずつ紹介します。HTMLで書かれた文書をJavaScriptで操作するとき、文書の内容は「DOM (Document Object Model)」と呼ばれる形式のデータを操作することになります。「DOM」という言葉の定義はちょっと抽象的で分かりづらいので、ひとまずここでは、今後「DOMオブジェクト」とか「DOMツリー」といった言葉を見た時「あっ、JavaScriptでHTMLの内容を操作する話をしてるんだな」と思えるようになれればよいでしょう。

::: details
実際には、JavaScript以外のプログラミング言語で操作する場合もこの「DOM」を使います。が、現代の現実的なユースケースの大半はJavaScriptで操作する場合です
実際には、JavaScript以外のプログラミング言語で操作する場合もこの「DOM」を使います。が、現代の話題になるユースケースの大半はJavaScriptで操作する場合です
:::

特定のHTMLを表すDOMがどのようになっているか見るために、例として下記のHTMLを用意しました。コピペして、`iij-bootcamp-dom`ディレクトリーに`2.html`という名前で保存してください。
Expand Down Expand Up @@ -1020,7 +1020,7 @@ document.body.appendChild(p);

### 要素を削除する

人生、誰しもやり直したいことがありますよね。メッセージを追記する機能を実装したまではよかったものの、もしかしたら間違ってあらぬことを投稿してしまって、削除したくなるかも知れません。そこで最後は、DOM要素を削除する方法を学ぶことで、追記したメッセージを削除する機能を作ってみましょう!
人生、誰しもやり直したいことがありますよね。メッセージを追記する機能を実装したまではよかったものの、もしかしたら間違ってあらぬことを投稿してしまって、削除したくなるかも知れません。そこで次は、DOM要素を削除する方法を学ぶことで、追記したメッセージを削除する機能を作ってみましょう!

まずは下準備として、前節で作成した`5.html``6.html`という名前にコピーします。それから、再び投稿する`button`要素のイベントリスナーの本体を編集します。

Expand Down Expand Up @@ -1050,14 +1050,81 @@ document.body.removeChild(p);

### ここまでのまとめ

- ユーザーなどがDOMの要素に対して何らかの操作を行った際実行するJavaScriptのコードを設定するには、要素の`addEventListener`というメソッドを使う
- DOMの要素に対して何らかのイベントが発生した(例えばユーザーがクリックした)際実行するJavaScriptのコードは、要素の`addEventListener`というメソッドを使うことで設定できる
- `addEventListener`に渡した関数が受け取る`Event`オブジェクトは、対象のイベントが発生したときの詳細な情報を含む
- 例えば、イベントオブジェクトの`target`というキーを通じて、イベントが発生した要素を取得することができる
- DOMツリーにおける、決まった要素に簡単にアクセスするには、HTMLの`id`属性や`class`属性と、`document.getElementById`メソッドや`document.getElementsByClassName`メソッドを組み合わせて使う
- 新しく要素を作ってDOMツリーに追加するには、`document.createElement`メソッドと、`親の要素.appendChild`メソッドを使う
- 新しく作った要素の内容として、テキストノードを作りたい場合は`document.createTextNode`メソッドを使う
- 要素を削除するには`親の要素.removeChild`メソッドを使う

### 要素の属性(attribute)を操作する

::: tip
この節は時間に余裕があればやりましょう。
:::

ここまで作ったものの他にSNSと言えばそう、...「炎上🔥」ですね。最後はメッセージを炎上させるボタンを作ることで、要素の属性を操作してみましょう。

::: tip
要素の「[属性(attribute)](https://developer.mozilla.org/ja/docs/Glossary/Attribute)」とは、要素の中身以外に

HTMLで属性を記述する場合、例えば次のように書きます:

```html
<p style="color: red;">これは style 属性を適用した p 要素</p>
```

上記の`p`要素は`style`という属性を設定しています。`style`属性にはCSSのスタイルを入力することで、対称の要素だけに適用する
:::

もちろん、この講義の知識で、ましてや単一のHTMLファイルでメッセージを炎上させるのは不可能でしょう。ここでは気軽に「炎上🔥」気分を味わう手段として、CSSによるスタイルを要素の設定することにします。JavaScriptで要素にCSSのスタイルを適用する手段はいくつかありますが、ここでは[`style`属性](https://developer.mozilla.org/ja/docs/Web/HTML/Global_attributes/style)[`setAttribute`メソッド](https://developer.mozilla.org/ja/docs/Web/API/Element/setAttribute)で設定することで実現します。

まずはこれまで通り、前節で作成した`6.html``7.html`という名前にコピーします。それからやはりこれまでと同様、`7.html`を開き、投稿する`button`要素のイベントリスナーの本体を編集します。前節で作成した「削除するボタン」を作成するコードの直後に、今度は「炎上するボタン」を作って`p`要素に`appendChild`しましょう。`button`要素の中身は炎上なので炎の絵文字「🔥」などがよいでしょう。

ボタンを正しく追加できれば、次👇のスクリーンショットにあるようなボタンがメッセージの左に表示されるでしょう。もちろん、うまくいかなかったらTAの方などに聞いてみてください!

![](./7-buttons.png)

最後に、追加した炎上🔥ボタンについて、`click`イベントのイベントリスナーを登録します。イベントリスナーの関数本体では、次のように`p`要素に対して`setAttribute`メソッドを呼び、`style`属性を設定しましょう:

```js
p.setAttribute(
"style",
`
color: red;
font-size: 200%;
font-weight: bold;
`
);
```

::: details
ℹ️「JavaScript構文概要」で紹介したバッククォートで囲った文字列リテラルを使用している点にご注意ください。複数行の文字列を設定しているため、読みやすくするためにバッククォートの文字列リテラルを採用しました。
:::

`setAttribute`メソッドに渡した第二引数、すなわち`style`属性の値は、CSSの構文で書かれています。詳細は割愛しますが、次のような意味を持ちます:

- [`color: red;`](https://developer.mozilla.org/ja/docs/Web/CSS/color): 文字の色を赤にする
- [`font-size: 200%;`](https://developer.mozilla.org/ja/docs/Web/CSS/font-size): 文字の大きさを、通常の2倍にする
- [`font-weight: bold;`](https://developer.mozilla.org/ja/docs/Web/CSS/font-weight): 文字の太さを太めにする

以上の通りにコードを書けていれば、下記のように動作する炎上🔥ボタンができてるはずです!

たけのこの里こそ至高

きのこ派は滅ぶべし

きのこなんてビスケットの部分とチョコの部分を別々に食べるようなもんじゃない。一緒にする意味あるの?

くっ、そうやって我々は明治の手のひらで踊らされてしまうのだ...

![](./7-flame-button.gif)

#### さらに興味がある人へ

先ほど「JavaScriptで要素にCSSのスタイルを適用する手段はいくつかあります」と触れたので、そのうちの一部をざっと紹介しておきます。要素の[`classList`](https://developer.mozilla.org/ja/docs/Web/API/Element/classList)[`className`](https://developer.mozilla.org/ja/docs/Web/API/Element/className)とHTMLの`<style>`タグ、あるいは`<link rel="stylesheet" />`による外部のCSSファイルを組み合わせることで、`p`要素にJavaScriptで`class`属性を設定してみてください。

## 参考文献(本文中で言及しなかったもののみ)

- [MacのSafariで「開発」メニューのデベロッパツールを使用する - Apple サポート (日本)](https://support.apple.com/ja-jp/guide/safari/sfri20948/mac)
Expand Down

0 comments on commit daf3965

Please sign in to comment.