JavaScript プルダウンメニューで指定ページへ

## はじめに

### 概要

このページではJavaScriptを使って「プルダウンメニュー操作によるページの切り替え」を実装します。

※この章は`JavaScript「超」入門 第2版`のchapter5-2「プルダウンメニューで指定ページへ　URLの操作、ブール属性の設定」の内容をさらに噛み砕いた解説ページです。chapter4までの内容を理解している前提で進めますので、用語などわからない箇所があれば入門本を振り返りましょう。

※コードはシンプルさを追求し、独自のものを用意しています。

### 本章の目的

- onchangeイベントを発動させる
- locationオブジェクトのhrefプロパティを変更して表示内容を切り替える
- selected属性を与えて初期表示を指定する

本章の内容をマスターすることで、別ページをリロードすることなくスムーズに切り替えることが可能になります。またページ遷移だけでなく、画像の差し替えやスライドショーなど、部分的な要素の入れ替えに必要な考え方を学習します。

完成イメージ

![画面収録 2021-01-29 12 03 57 mov](https://user-images.githubusercontent.com/70306357/106226353-4b83a800-622a-11eb-8533-21ce4803a73b.gif)

## テキスト

### 事前準備

この章で必要なファイルを準備します。

```
新規ディレクトリ・ファイルを作成
monigate/javascript/lesson2
∟ index.html
∟ index-en.html
∟ index-zh.html
∟ style.css
∟ location.js
```

日本語、英語、中国語のページをそれぞれ用意します。
構造はすべて同じで
・header要素内のh1要素（タイトル）
・main要素内のp要素（本文）
この2ヵ所のテキストのみ変えています。 

```html:lesson2/index.html
<html>
  <head>
    <meta charset="UTF-8">
    <title>JS:プルダウンメニューでページ切り替え</title>
    <link rel="stylesheet" href="style.css">
  </head>
  <body>
    <header>
      <h1>プルダウンメニューでページ切り替え</h1>
    </header>
    <main>
      <form id="form">
        <select name="select">
          <option value="index.html">日本語</option>
          <option value="index-en.html">English</option>
          <option value="index-zh.html">中文</option>
        </select>
      </form>
      <p>日本語のページ</p>
    </main>
    <footer>
      <p>Monigate</p>
    </footer>
    <script src="location.js"></script>
  </body>
</html>
```
```html:lesson2/index-en.html
<html>
  <head>
    <meta charset="UTF-8">
    <title>JS:プルダウンメニューでページ切り替え</title>
    <link rel="stylesheet" href="style.css">
  </head>
  <body>
    <header>
      <h1>Switch pages with pull-down menu</h1>
    </header>
    <main>
      <form id="form">
        <select name="select">
          <option value="index.html">日本語</option>
          <option value="index-en.html">English</option>
          <option value="index-zh.html">中文</option>
        </select>
      </form>
      <p>English Page</p>
    </main>
    <footer>
      <p>Monigate</p>
    </footer>
    <script src="location.js"></script>
  </body>
</html>
```
```html:lesson2/index-zh.html
<html>
  <head>
    <meta charset="UTF-8">
    <title>JS:プルダウンメニューでページ切り替え</title>
    <link rel="stylesheet" href="style.css">
  </head>
  <body>
    <header>
      <h1>使用下拉菜单切换页面</h1>
    </header>
    <main>
      <form id="form">
        <select name="select">
          <option value="index.html">日本語</option>
          <option value="index-en.html">English</option>
          <option value="index-zh.html">中文</option>
        </select>
      </form>
      <p>中文页面</p>
    </main>
    <footer>
      <p>Monigate</p>
    </footer>
    <script src="location.js"></script>
  </body>
</html>
```
```css:lesson2/style.css
h1 {
  text-decoration: underline;
}
```
```javascript:location.js
'use strict';
```

### 選択したタイミングでページ遷移する

jsファイルを編集します。

```javascript:location.js
'use strict';

document.getElementById('form').select.onchange = function() {
  location.href = document.getElementById('form').select.value;
}
```
index.htmlをブラウザで開き、挙動を確認しましょう。

プルダウンメニューを操作すると、すぐにページが切り替わります。

しかし、今の状態では日本語ページに戻れなくなりますよね？

この問題は後ほど解決するので、先に今回の記述を解説していきましょう。

<br>

`解説`

```javascript:location.js
document.getElementById('form').select.onchange = function() {
```
この一行で、フォームの内容が変わったときにfunctionが発動するようになります。

#### onchangeイベント

onchageイベントは、フォームに入力された内容が変わったときに発動します。テキストフィールドなら入力内容が変わったとき、プルダウンメニューであれば選択項目が切り替わったときに発動します。

#### getElementById('form').select.onchangeを紐解く

onchangeの対象は**フォーム要素の部品であるselect要素**です。したがってformタグにはid名"form"を指定し、さらにselectタグにはname属性"select"を指定することで`getElementById('form').select.onchange`の形でselect要素の情報を取得できるようになります。

***※フォーム部品（フォーム要素の子要素のこと）を取得するには`フォーム部品のname属性を指定する`というルールがあります。***

***（例）***

```html:sample.html
<select name="hoge">
フォーム部品(select要素）を取得するには「name="hoge"」のように任意のname属性を命名する必要がある
```
<br>

次に二行目を見ていきます。


```javascript:location.js
location.href = document.getElementById('form').select.value;
```
この記述でselect要素のvalueプロパティ（要素の中身）を読み取り、URLに反映します。

#### locationオブジェクト

locationオブジェクトは、windowオブジェクトなどと同じく、ブラウザに初めから組み込まれているオブジェクトです。URLを調べたり、閲覧履歴を管理したりする機能があります。

#### hrefプロパティ
hrefプロパティは表示するページのURLを意味します。つまり、hrefプロパティの値を変更すると、すぐに別ページに移動します。

#### select要素でのvalueの使い方

ここでひとつ疑問が生まれます。

htmlではoption要素にvalue属性（つまり遷移先のURL）を指定しました。
しかし、この記述では`document.getElementById('form').select.value;`とselect要素のvalueを読み取っています。

これは**プルダウンメニューの場合はoption要素のvalueを調べるために、その親要素であるselect要素のvalueを読み取る**という構造になっているからです。

つまりselect要素のvalueを指定すれば、その中身のoption要素のvalueを読み取るようにプログラミングされている、と言い換えることもできます。

JavaScriptを実装していくと思ったように値を取得できずにハマることが多々あります。そんなときは「HTMLとJavaScriptのルールってどうなってるのかな？」と原点に立ち返ると解決の糸口が見つかったりします。

### 最初に選択されている項目を切り替える

では次に、ページが切り替わったときにプルダウンメニューの初期選択項目を表示に合わせるように改良します。

<img width="600" alt="スクリーンショット 2021-01-28 18 53 33" src="https://user-images.githubusercontent.com/70306357/106121161-95bd4880-619a-11eb-9837-2752b44ffbf1.png">

実は各HTMLファイルを編集することで対応できます。しかし、非効率なのでここはプログラミングで解決します。

そのためにはoptionタグに**selected属性**を追加します。

#### selected属性

プルダウンメニューをはじめ、ラジオボタンやチェックボックスなどの`選択項目の初期選択項目を指定`する属性。

***（例）***

```html:sample
<select>
  <option>りんご</option>
  <option>みかん</option>
  <option>もも</option>
</select>
→ 初期設定値は一番上の「りんご」になる

<select>
  <option>りんご</option>
  <option selected>みかん</option>
  <option>もも</option>
</select>
→ 初期設定値は「みかん」になる
```

では具体的に実装していきましょう。

まず、それぞれの言語のページに目印をつけるため、各htmlファイルに**lang属性**を追加します。
追加するのはhtmlファイルの`<html>タグ`です。

```html:lesson2/index.html
<html lang="ja">
```
```html:lesson2/index-en.html
<html lang="en">
```
```html:lesson2/index-zh.html
<html lang="zh">
```


#### lang属性

要素の内容がどのような言語で記述されているかを表します。html要素にlang属性を持たせることで、ページ全体の言語を指定することができます。対応する属性値には言語コードと呼ばれる、決められたコードを記述します。

【言語コード】
日本語 => ja
英語 => en
中国語 => zh

> Googleは「lang属性を見ていない」という情報もあり、言語指定の方法としてlang属性は有効なのか？といった声もありますが、ここではあくまで目印としてlang属性を指定することにします。

これで準備ができたのでjsファイルを編集していきます。

次のコードを追加してください。

```javascript:location.js

'use strict';

// ここから追加
const language = document.querySelector('html').lang;

if(language === 'ja') {
  document.querySelector('option[value="index.html"]').selected = true;
} else if(language === 'en') {
  document.querySelector('option[value="index-en.html"]').selected = true;
} else if(language === 'zh') {
  document.querySelector('option[value="index-zh.html"]').selected = true;
}
// ここまで

document.getElementById('form').select.onchange = function() {
  location.href = document.getElementById('form').select.value;
}
```
ブラウザで確認しましょう。
ページを切り替えるとプルダウンの初期選択項目も正しく選ばれるようになりました。

`解説`

上から見ていきます。

```javascript:location.js
const language = document.querySelector('html').lang;
```
querySelectorメソッドを使ってhtml要素のlang属性を取得しています。

#### querySelectorメソッド
セレクタを指定して要素を取得するメソッド。CSSのセレクタ指定と同じ感覚で使えるので便利で簡単です。割と最近登場したメソッドでもあります。

もし該当する要素が複数ある場合、「最初にマッチした要素」を一つだけ取得します。
複数の要素を一度に取得したい場合は`querySelectorAllメソッド`を使用します。詳細は別章「イメージの切り替え」にて解説します。

#### 属性と属性値を読み取る

次にif文を見ていきます。

```javascript:location.js
if(language === 'ja') {
  document.querySelector('option[value="index.html"]').selected = true;
} else if(language === 'en') {
  document.querySelector('option[value="index-en.html"]').selected = true;
} else if(language === 'zh') {
  document.querySelector('option[value="index-zh.html"]').selected = true;
}
```

ここで`querySelector('option[value="index.html"]')`という記述がありますね。

これはoption要素のうち**value属性とそれに対応する属性値**がマッチするものを取得する、という意味です。

つまり`language === 'ja'`の場合で考えると、option要素のvalue値が"index.html"のものにselected属性を付与することになるので、初期選択項目が「日本語」になってくれるのですね。

jsファイルからselected属性を与えるときは `selected = true`を記述（代入）します。逆に取り除くときは`selected = false`とします。

> ☝️ワンポイント
selected属性やchecked属性など、真偽値（true/false)で有効と無効を指定する属性のことをブール属性（またはブーリアン属性）と言います。boolean(真偽）という言葉はこれからもたくさん出てくるので覚えておきましょう。

`余談`

ところで今回の記述では、if文の手前と中身で似たようなコードを書きました。

- if文の手前：属性だけを取得

```javascript:location.js
const language = document.querySelector('html').lang;
// lang属性を取得 => document.querySelector('html[lang="ja"]')とは書かない
```

- if文の中身（処理内容）：属性と属性値を取得

```javascript:location.js
document.querySelector('option[value="index.html"]').selected = true;
// value属性の属性値"index.html"まで取得
```

<br>

この違いを理解するために、次のコードを見てください。

```javascript:location.js
if(document.querySelector('html[lang="ja"]')) {
  document.querySelector('option[value="index.html"]').selected = true;
} else if (document.querySelector('html[lang="en"]')) {
  document.querySelector('option[value="index-en.html"]').selected = true;
} else if(document.querySelector('html[lang="zh"]')) {
  document.querySelector('option[value="index-zh.html"]').selected = true;
}
```

if文の( )部分＝条件式ごとに属性と属性値を取得するように書き換えてみました。

・・・とても長ったらしくて読みにくいですよね。

つまり完成形のコードは`条件式を簡潔にするために、if文を書く前に属性だけ取得した`と言えます。

いろいろな使い方がありますので、たくさんコードに触れて覚えていきましょう。

## おわりに

次は画像の切り替えを解説します。