マウスオーバーでJSONファイルからデータを読み込む：HTMLとJavaScriptによる動的説明表示の実装

## マウスオーバーで動的に外部 JSON ファイルを読み込みたい

↓ こういうことをしたいが、ダイナミックにローディングさせたい。

| ![画面収録-2024-10-27-12.37.22-fix.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78776/0584af25-cc63-ed1e-a6a0-3c6e1fb06728.gif "hoverのように、HTML要素にマウスオーバーするとJavascriptで外部JSONファイルを読み込み、成形して表示する例") |
| :-- |
| マウスオーバー時のイメージ（表示される説明文は外部 JSON ファイル） |

この記事は HTML と JavaScript を使って CSS で言う `hover` のように、特定要素をマウスオーバー(`mouseover`)した際に、<font color="darkorange">**同じサイト内にある JSON データを動的に読み込み、その内容をページ内に表示する方法**</font>を解説しています。

[「外部JSONファイル 動的 マウスオーバー 読み込み」でググって](https://www.google.com/search?q=site:qiita.com+%E5%A4%96%E9%83%A8JSON%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB+%E5%8B%95%E7%9A%84+%E3%83%9E%E3%82%A6%E3%82%B9%E3%82%AA%E3%83%BC%E3%83%90%E3%83%BC+%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%81%BF)みても、ドンピシャの Qiita 記事がなかったので自分のググラビリティとして。

:::note warn
この記事では、Javascript と JSON の**ファイルは同じドメイン内に設置されていることを前提**としています。

別ドメインから JSON データを取得したい（クロスドメインで取得したい）場合は、[`JSONP`](https://ja.wikipedia.org/wiki/JSONP) などを使ってください。`JSONP` を使う場合は、大半がセキュリティの話しになるため、この記事では割愛します。
:::

## Let's Load JSON File OnMouseOver

具体的には、以下のイメージのように、用語をマウスオーバーすると用語の概要を表示させたいのです。ただし、この時 <font color="darkorange">**HTML もしくは Javascript 内には表示内容を埋め込まずに、用語ごとに概要を記載した JSON ファイルを動的に読み込んで欲しい**</font>のです。

| ![画面収録-2024-10-27-12.37.22.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78776/e2c6cb44-3a71-ea7a-f069-fc2eb8728d46.gif "hoverのように、HTML要素にマウスオーバーするとJavascriptで外部JSONファイルを読み込み、成形して表示する例") |
| :-- |
| マウスオーバー時のイメージ（表示される説明文は外部 JSON ファイル） |

以下は、HTML 内に <code>&lt;span id="&lt;your_id&gt;" class="dict"&gt;ここに用語&lt;/span&gt;</code> があった場合、「ここに用語」をマウスオーバーすると <code>&lt;your_id&gt;.json</code> ファイルを動的に読み込み表示する、シンプルなサンプルです。

### ディレクトリ構造

```shell-session
$ tree
.
├── about_hash_value.json ... 動的に読み込みたいデータ
├── index.html .............. メインの HTML ファイル
└── yourScript.js ........... 読み込み用のスクリプト
```

### 動的に読み込みたいデータ

```json:about_hash_value.json
{
    "description": "<strong><font color=darkorange>ハッシュ値とは「データの情報紋」</font>です。人間の指紋のように、データを特定するために使われる数値です</strong>。ハッシュ値は、データをハッシュ関数を通すことで生成され、データとハッシュ・アルゴリズムが同じであれば必ず同じハッシュ値が生成されます。異なるデータで同じハッシュ値になることもあり、セキュリティ上、なるべく一意のハッシュ値が必要な場合は「暗号学的ハッシュ関数」を使用します。"
}
```

### メインのHTMLファイル

```html:index.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>動的読み込みのサンプル</title>
    <style>
        .dict {
            text-decoration: underline dotted;
        }
    </style>
</head>
<body>
    <div>
        データの<span id="about_hash_value" class="dict">ハッシュ値</span>をキーとして、データベースに登録することで、データの検索を高速化できます。
    </div>
    <div id="show_about"></div>

    <script src="./yourScript.js"></script> <!-- 後述のJavaScriptをここに指定 -->
</body>
</html>
```

### 読み込み用のスクリプト

```javascript:yourScript.js
document.addEventListener('DOMContentLoaded', () => {
    // 「dict」クラスを持つ要素を取得
    const terms = document.querySelectorAll('.dict');

    terms.forEach(term => {
        term.addEventListener('mouseover', async () => {
            const termId = term.getAttribute('id');
            const displayElement = document.getElementById('show_about');

            try {
                // JSONファイルのパスを構築
                const response = await fetch(`./${termId}.json`);

                if (!response.ok) {
                    throw new Error('説明ファイルが見つかりません');
                }

                // JSONを取得して解析
                const data = await response.json();

                // 内容を表示
                displayElement.innerHTML = `<p>${data.description}</p>`;
            } catch (error) {
                console.error('エラー:', error);
                displayElement.innerHTML = '<p>説明の読み込みに失敗しました。</p>';
            }
        });

        // マウスアウトで説明をクリア
        term.addEventListener('mouseout', () => {
            const displayElement = document.getElementById('show_about');
            displayElement.innerHTML = '';
        });
    });
});
```

### 動作確認

上記を Web サーバー経由で公開し、ブラウザで確認します。

VSCode であればビルトイン Web サーバー経由（プレビュー）や、簡易サーバーを備えてるプログラム言語（例えば PHP や Python など）で確認するのが手っ取り早いと思います。

```shell-session:Python3の簡易Webサーバーで確認する例（この場合 http://localhost:8000/ で確認可）
$ python3 -m http.server 8000
Serving HTTP on :: port 8000 (http://[::]:8000/) ...
```