HTMLとJavaScriptの連携

# HTMLとJavaScriptの連携ができるとどうなる？
ボタンを押したときにダイアログを出す。
通信して取得したデータをWebページに表示する。
など動きのあるページが作れるようになる！

htmlだけではできない動きがJavaScriptによってできるようになるのでできることが広がる。

# 前提
JavaScriptの基礎を理解していること。
htmlからJavaScriptの読み込みができる。 (以下)

```index.html
<!DOCTYPE html>
<html lang='en'>
<head>
    <meta charset='UTF-8'>
    <meta name='viewport' content='width=device-width, initial-scale=1.0'>
    <script type="text/javascript" src='./main.js'></script>
    <title>Document</title>
</head>
<body>
    <p>Hello World</p>
</body>
</html>
```

本記事ではこれをベースに進めていく。

# ボタンを押したらダイアログを表示する

このボタンを押したら
<img width="150" alt="スクリーンショット 2020-07-26 19.21.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/06efa57f-bcb4-56ec-1765-1d39181dd06a.png">

こんな感じのダイアログを出す。
<img width="451" alt="スクリーンショット 2020-07-26 19.29.43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/9bb37b2c-4370-c5b8-18e1-968571dfe654.png">

全体像は以下
<img width="1208" alt="スクリーンショット 2020-07-26 19.36.36.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/9dbeb36e-0667-9a7d-605c-402ede349bd5.jpeg">

3ステップで作成していく。








## htmlでボタンを表示する
まずはボタンを作る

```index.html
<body>
    <button>ここを押してね！</button>
</body>
```

buttonタグで囲むだけ。

これを書いたらブラウザでボタンが表示されていることを確認。
押してもなにもおきない。

## JavaScript側に関数を用意

```main.js
const alertHelloWorld = () => {
    alert("HelloWorld");
}
```

`alert`は文字列をダイアログで表示するための関数。

## ボタンを押したときに関数を呼び出す。
ボタンタグに`onclick`を追加する。

```index.html
<body>
    <button onclick="alertHelloWorld()">ここを押してね！</button>
</body>
```

これでブラウザで確認できる。
関数名だけではなく`()`をつけることに注意。

# JavaScriptから文字をWebページに表示させる
|ボタン押す前|ボタン押した後|
|:--:|:--:|
|<img width="221" alt="スクリーンショット 2020-07-26 22.49.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/b6080856-29c3-8db5-76de-67cd9e79ba60.png">|<img width="215" alt="スクリーンショット 2020-07-26 22.49.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/323b0c9d-7fe7-f5f4-ad09-32affbb89ea0.png">|
文字が変わる

## html側の用意
最初に表示する文字をhtmlに仕込んでおく。

```index.html
<body>
    <div id="canvas">ここに文字をいれる</div>
    <button onclick="drawCanvas()">ここを押してね！</button>
</body>
```

ポイントは`<div id="canvas">`。
div要素にidをつける。
idをつけることでJavaScript側から要素を取得することが可能になる。
id名はとくに決まりはないが、ここでは何かしらを描くところって意味で`canvas`という名前にした。

## 文字を変更する
JavaScript側でやることは
1. idが"canvas"の要素を取得し、
2. そこに新しい文字列をつっこむ
の2つ。

それは以下のように書ける

```main.js
const drawCanvas = () => {
    const canvas = document.getElementById("canvas");
    canvas.innerHTML = "Hello JavaScript!";
}
```

<img width="457" alt="スクリーンショット 2020-07-26 23.15.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/5b85226a-822e-cf59-52a7-785a35f12e13.png">
この図の黄色い部分が`innerHTML`

#### ポイント

IDを用いた要素の検索。

```.js
const 要素 = document.getElementById("ID名");
```

要素の中身の変更

```.js
要素.innerHTML = "新しい中身";
```

これでブラウザでボタンを押したときに表示が変わることが確認できる。

# 最初に表示する文字もJavaScriptから設定する。
なるべくJavaScript側に書きたいので最初に表示する文字もJavaScript側で書きたい。

読み込み時に設定するためにmain.jsをで以下のように書く。

```main.js
// 初期化用の関数を用意
const initialize = () => {
    const canvas = document.getElementById("canvas");
    canvas.innerHTML = "ここに文字をいれる";
}

// 読み込み時に呼び出す。
initialize();
```

html側には文字を入れないでおく

```index.html
<body>
    <div id="canvas"></div>
    <button onclick="drawCanvas()">ここを押してね！</button>
</body>
```

で、これでブラウザで確認すると、表示されない。
<img width="196" alt="スクリーンショット 2020-07-27 22.44.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/49bdfc59-6540-604c-76e0-1b2fa91e45fe.png">

そしてコンソールには以下のようなエラーが表示される。

```
uncaught TypeError: Cannot set property 'innerHTML' of null at initialize
```

initializeの該当部分は以下

```main.js
    const canvas = document.getElementById("canvas");
    canvas.innerHTML = "ここに文字をいれる";
```
「nullにはinnerHTMLっていうプロパティーないよ」
=> canvasはnullである (何にも入ってないって意味)
=> document.getElementById("canvas")が失敗している。

と推測できる。


で、じゃあなぜ失敗するかというと、jsの読み込みのタイミングの問題。
現状以下のような流れになっている。

<img width="482" alt="スクリーンショット 2020-07-26 21.53.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/60760f3a-060c-779d-b18b-b0b933e781a8.png">

bodyの中身を描画する前にjsの読み込みが走っているのでまだ「canvas」がないってこと。
そこでjsの読み込みタイミングを遅くする。
そのやり方の一つが以下。

```index.html
// before
<script type="text/javascript" src='./main.js'></script>
// after
<script type="text/javascript" src='./main.js' defer></script>
```
main.jsを読み込むときにdeferをつける。
するとちゃんと初期化されるようになる。

# JavaScriptから色を変える
idから取得した要素は文字の内容を変えるだけでなく他にもいろいろ変えられる。
そこでまずは色を変えてみる。

<img width="211" alt="スクリーンショット 2020-07-27 23.00.43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/01b0980c-58ac-43d9-4cd0-2e071c993d01.png">

```main.js
const drawCanvas = () => {
    const canvas = document.getElementById("canvas");
    canvas.innerHTML = "Hello JavaScript!";
    canvas.style.color = 'red'; // <-　ここ
}
```

色の設定は決められた文字ではなくカラーコードでもOK

<img width="192" alt="スクリーンショット 2020-07-27 23.02.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/e6c45cc7-be09-6208-f5b8-c7ffca580750.png">

```main.js
const drawCanvas = () => {
    const canvas = document.getElementById("canvas");
    canvas.innerHTML = "Hello JavaScript!";
    canvas.style.color = '#00FF00';
}
```


他にもいろいろ変えられるのでcssで変えられるものを試してみるとよい。

<img width="192" alt="スクリーンショット 2020-07-27 23.08.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/1936a881-6651-3d3b-f260-8333e4e5b58e.png">


```main.js
const drawCanvas = () => {
    const canvas = document.getElementById("canvas");
    canvas.innerHTML = "Hello JavaScript!";
    canvas.style.color = '#00FF00';
    canvas.style.backgroundColor = 'red'; // 背景色変更
    canvas.style.padding = '10px'; // 領域を広くする
}
```


# 応用するとこんなこともできる
ここはやらなくて大丈夫。
非同期とかできるようになるとこんな感じのアニメーションとかも作れるようになる。

![animation_js.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/15544edf-9e1a-e006-6827-11a0c98a4b7b.gif)

```.js
const sleep = (msec) => new Promise(resolve => setTimeout(resolve, msec));

const drawTextAsync = async () => {
    const canvas = document.getElementById("canvas");
    canvas.style.backgroundColor = 'white'; 
    canvas.style.color = 'black'
    canvas.innerHTML = "　";
    await sleep(100);
    const word = "Hello JavaScript!";
    for (var i = 0; i < word.length; i++) {
        const content = word.substr(0, i+1);
        canvas.innerHTML = content;
        await sleep(100);
    }
    canvas.style.backgroundColor = 'red'; 
    canvas.style.color = 'white'
}
```