5.8 DOM(Document Object Model)

(1/1)
ステーキメニュー - DOM
JavaScriptには、HTMLやXMLといった構造化テキストを扱うために、DOMという仕組みが用意されている。DOM とは Document Object Model の略で、文字通り、構造化テキストをオブジェクトとして扱うことができる。
今回は、複数のラジオボタンやチェックボックスを使ってステーキセットのメニューを表示し合計金額を計算するプログラムを作ることで、DOM について学ぶ。DOM を活用すると、ブラウザの表示を動的に変更することができるようになる。

目次

サンプル・プログラム

圧縮ファイルの内容
selectSteakMenu.htmlサンプル・プログラム。
selectSteakMenu2.htmlサンプル・プログラム。メニューアイテムをオブジェクト化。

HTMLの構造

HTMLの構造 - DOM
すべてのHTMLコンテンツは、タグをノード(結節)にしたツリー構造になっている。たとえば "selectSteakMenu.html" の構造(前半部分のみ)は上図のようなツリー構造になっている。
DOM は、このツリー構造全体を指す概念で、JavaScriptの Documentインターフェースは、ブラウザに読み込まれた自分自身の DOM を表す。

NodeList

  53: /**
  54:  * 合計金額を計算する.
  55:  * @param   なし
  56:  * @return  なし
  57: */
  58: function calc() {
  59:     //合計金額
  60:     let price = 0;
  61:     //ステーキ(ラジオ)
  62:     let weights = document.getElementsByName('weight');     //NodeList
  63:     for (let i = 0i < weights.lengthi++) {
  64:         if (weights[i].checked) {
  65:             price +Number(weights[i].value);
  66:         }
  67:     }
  68:     //サイドメニュー(チェックボックス)
  69:     let sides = document.getElementsByName('side');         //NodeList
  70:     for (let i = 0i < sides.lengthi++) {
  71:         if (sides[i].checked) {
  72:             price +Number(sides[i].value);
  73:         }
  74:     }
  75:     //合計値を表示する.
  76:     document.getElementById('price').innerHTML = price.toLocaleString();
  77: }

ユーザー関数 calc は、ラジオボタンやチェックボックスが変化すると呼び出され、合計金額を計算して表示する。

document.getElementsByName()は、DOM である Documentインターフェース の中から、引数で指定した nameNodeListオブジェクトを取り出す。NodeListDOM の一部である。

NodeList の要素の数は lengthプロパティに格納される。ここではステーキの重さを選択する name=weight の名前のオブジェクトが3つあるから、weights.length の値は3だ。各々の要素はオブジェクト配列の形で格納されている。
そこで、そのオブジェクトにチェックが付いているかどうかを checkedプロパティを使って判定し、チェックが付いていれば、その値(valueプロパティ)を合計金額に加算する。

サイドメニューを選択する name=side に対しても同様の処理を行う。
ここで、name=weight はラジオボタンなので if (weights[i].checked) は一度しか true にならない。これに対して、name=side はチェックボックスなので if (sides[i].checked) は複数回 true になり得る。

合計金額 price が計算できたら、id=price のオブジェクトに書き込む。idを含むオブジェクトを求めるには document.getElementsByName()メソッドを利用する。
ここではspanタグの中にHTMLとして記入するので、innerHTMLプロパティに代入する。

  79: /**
  80:  * 表示をリセットする.
  81:  * @param   なし
  82:  * @return  なし
  83: */
  84: function reset() {
  85:     //ステーキ(ラジオ)
  86:     let weights = document.getElementsByName('weight');     //NodeList
  87:     for (let i = 0i < weights.lengthi++) {
  88:         weights[i].checked = false;
  89:     }
  90:     //サイドメニュー(チェックボックス)
  91:     let sides = document.getElementsByName('side');         //NodeList
  92:     for (let i = 0i < sides.lengthi++) {
  93:         sides[i].checked = false;
  94:     }
  95:     //合計値を表示する.
  96:     document.getElementById('price').innerHTML = '';
  97: }

表示内容をリセットするユーザー関数 reset は、calcの応用である。

メニューをオブジェクト化する

メニューの選択肢を容易に変更できた方が実業務に即応できるだろう。
そこで、前回「5.7 制御をオブジェクトで置換」で学んだ手法の応用で、メニューアイテムを、あらかじめオブジェクト配列に代入しておき、これを画面に表示するようにしてみた。サンプル・プグラムの2つ目 "selectSteakMenu2.html" が、それである。

  55: //メニューアイテム(オブジェクト化)
  56: MenuItems = [
  57: {
  58:     type: 'radio',              //inputのtype
  59:     name: 'weight',             //name属性
  60:     func: 'calc()',             //onChangeイベント
  61:     value: 1000,                //valueの値
  62:     label: '100g  1,000円'    //表示ラベル
  63: },
  64: {
  65:     type: 'radio',
  66:     name: 'weight',
  67:     func: 'calc()',
  68:     value: 2000,
  69:     label: '200g  2,000円'
  70: },
  71: {
  72:     type: 'radio',
  73:     name: 'weight',
  74:     func: 'calc()',
  75:     value: 3000,
  76:     label: '300g  3,000円'
  77: },
  78: {
  79:     type: 'checkbox',
  80:     name: 'side',
  81:     func: 'calc()',
  82:     value: 100,
  83:     label: 'ライス  100円'
  84: },
  85: {
  86:     type: 'checkbox',
  87:     name: 'side',
  88:     func: 'calc()',
  89:     value: 120,
  90:     label: 'サラダ  120円'
  91: },
  92: {
  93:     type: 'checkbox',
  94:     name: 'side',
  95:     func: 'calc()',
  96:     value: 150,
  97:     label: 'コーヒー 150円'
  98: }
  99: ];

オブジェクト配列 MenuItems には、ラジオボタンまたはチェックボックスに表示する要素を代入しておく。

 101: /**
 102:  * メニューを表示する.
 103:  * @param   Object items メニューアイテム
 104:  * @return  なし
 105: */
 106: function dispMenu(items) {
 107:     let weights = '';
 108:     let sides   = '';
 109:     items.forEach (function (element, index) {
 110:         if (element.name == 'weight') {
 111:             weights +`
 112: <li><input type="${element.type}" name="${element.name}" value="${element.value}" onChange="${element.func};">${element.label}</li>
 113: `;
 114:         } else if (element.name == 'side') {
 115:             sides +`
 116: <li><input type="${element.type}" name="${element.name}" value="${element.value}" onChange="${element.func};">${element.label}</li>
 117: `;
 118:         }
 119:     });
 120:     document.getElementById('weight').innerHTML = weights;
 121:     document.getElementById('side').innerHTML   = sides;
 122: }

ユーザー関数 dispMenu によって、オブジェクト配列 MenuItems の内容を所定の場所に展開する。

コラム:DOMは応用範囲比が広い

食券販売機
DOM の使い方はお分かりになったろうか。
これまでのデータ構造と違い、概念的な部分が多く、取っつきにくいかもしれない。だが、冒頭で述べたように、DOM を活用することで動的なホームページを作ることができるようになる。
たとえば、"selectSteakMenu2.html" で使ったメニューアイテムは、現実の業務ではデータベースのマスタとして用意されていることだろう。
そこで、非同期通信でデータベースAPIに問い合わせ、受け取ったアイテムを DOM を使って表示する。こうすれば、ブラウザ側(アプリ)を変更することなく、データベースを変更するだけで表示メニュー内容を変更することができる。
また、物販サイトなら、在庫データベースに問い合わせ、購入可能な数量を表示することもできるだろう。

DOM はJavaScriptだけでなく、PHPやPythonなどのプログラミング言語にも実装されており、覚えておくと応用が効く。
6.8 XMLファイル」で再び DOM を扱う。
(この項おわり)
header