このブログはプログラム開発や学習などの際に役立つ知識や情報を発信するエンジニアのためのトータル技術ブログです。
ご意見やご要望にも積極的に答えていきますので、お気軽にお問い合わせください。

記事へのリクエストはこちら

② JavaScript で表計算アプリを作ってみる

HTML/CSS
スポンサーリンク

こんにちは!あっきーです!

前回 JavaScript の DOM 機能を使って表計算アプリを一緒に作りましたね!

ですが、同じ処理を繰り返したりで無駄に長くなってることからイケてないコードですと言ったかと思います 笑

とりあえず DOM 機能の基本的な使い方を把握しましょうがコンセプトだったのでしょうがないのです。

け、けっして当時の自分を擁護するためじゃないんだから!!

 

てことで!今回は同じ Webアプリ でコードをスマートにしたバージョンを公開します!

良いコードかどうかはわからないけど、大体の人がこんな感じの実装になるでしょうってくらいだと思います!

てか、本音を言いますとこれが今の僕の限界ですww

ではやっていきましょう!

スポンサーリンク

さいしょに

今回つくるアプリケーションの動作を動画にしましたので確認しましょう!

 

また、前回のコードなどを参照したい人はこちらの記事も合わせてチェックしてみてください!

① JavaScript で表計算アプリを作ってみる
きつね先生 今日は JavaScript で表計算アプリをつくりましょう! わんぽち なんだかとっても難しそうだわん きつね先生 そん...

コードプレビュー

まずは自分のローカル環境で動作確認を行いたい人はしたの HTML コードと JavaScript のコードをテキストエディタにコピペしてファイルを作成してください。

※ HTML の宣言や body タグなどは省略してるので個々で追加しておいてください。

・index.html

<table>
    <tr>
        <th>交通機関</th>
        <th>単価</th>
        <th>利用区分</th>
        <th>合計</th>
    </tr>
    <tr>
        <td>
            <select>
                <option>地下鉄</option>
                <option>従来線</option>
            </select>
        </td>
        <td>    
            <input type="text" class="price">
        </td>
        <td>
            <select class="traffic">
                <option value="0"></option>
                <option value="1">片道</option>
                <option value="2">往復</option>
            </select>
        </td>
        <td>
            <input type="text" class="total">
        </td>
    </tr>
    <tr>
        <td>
            <select>
                <option>地下鉄</option>
                <option>従来線</option>
            </select>
        </td>
        <td>    
            <input type="text" class="price">
        </td>
        <td>
            <select class="traffic">
                <option value="0"></option>
                <option value="1">片道</option>
                <option value="2">往復</option>
            </select>
        </td>
        <td>
            <input type="text" class="total">
        </td>
    </tr>
    <tr>
        <td>
            <select>
                <option>地下鉄</option>
                <option>従来線</option>
            </select>
        </td>
        <td>    
            <input type="text" class="price">
        </td>
        <td>
            <select class="traffic">
                <option value="0"></option>
                <option value="1">片道</option>
                <option value="2">往復</option>
            </select>
        </td>
        <td>
            <input type="text" class="total">
        </td>
    </tr>
    <tr>
        <td align="right" colspan="3"><strong>合計</strong>
        </td>
        <td>
            <input type="text" class="field_total">
        </td>
    </tr>
</table>

<table>
    <tr>
        <th>宿泊等</th>
        <th>単価</th>
        <th>泊数(数量)</th>
        <th>合計</th>
    </tr>
    <tr>
        <td>
            <select>
                <option>宿泊</option>
                <option>食費</option>
                <option>地下鉄</option>
            </select>
        </td>
        <td>    
            <input type="text" class="price">
        </td>
        <td>
            <select class="count">
                <option>0</option>
                <option>1</option>
                <option>2</option>
                <option>3</option>
            </select>
        </td>
        <td>
            <input type="text" class="total">
        </td>
    </tr>
    <tr>
        <td>
            <select>
                <option>宿泊</option>
                <option>食費</option>
                <option>地下鉄</option>
            </select>
        </td>
        <td>    
            <input type="text" class="price">
        </td>
        <td>
            <select class="count">
                <option>0</option>
                <option>1</option>
                <option>2</option>
                <option>3</option>
            </select>
        </td>
        <td>
            <input type="text" class="total">
        </td>
    </tr>
    <tr>
        <td>
            <select>
                <option>宿泊</option>
                <option>食費</option>
                <option>地下鉄</option>
            </select>
        </td>
        <td>    
            <input type="text" class="price">
        </td>
        <td>
            <select class="count">                   
                <option>0</option>
                <option>1</option>
                <option>2</option>
                <option>3</option>
            </select>
        </td>
        <td>
            <input type="text" class="total">
        </td>
    </tr>
    <tr>
        <td align="right" colspan="3"><strong>合計</strong>
        </td>
        <td>
            <input type="text" class="field_total">
        </td>
    </tr>
</table>

総合計<input type="text" name="all_total">
<button id="button">確認</button>

<script src="app.js"></script>

app.js

document.addEventListener('change',function(e){   
    var price = document.querySelectorAll('.price');
    var total = document.querySelectorAll('.total');
    var traffic = document.querySelectorAll('.traffic');
    var count = document.querySelectorAll('.count');
    var field_total = document.querySelectorAll('.field_total');
    var all_total = document.querySelector('input[name=all_total]');

    //1つめの合計の初期値設定
    var index0 = 0;

    //2つめの合計の初期値設定
    var index1 = 0;

    //計算の初期値設定
    var ini_val = 0;

    for(var i = 0; i < 3; i++){
      index0 += (ini_val = parseInt(price[i].value || 0) * parseInt(traffic[i].value || 0));
      total[i].value = price[i].value == "" ? "" : ini_val;
      index1 += (ini_val = parseInt(price[i+3].value || 0) * parseInt(count[i].value || 0));
      total[i+3].value = price[i+3].value == "" ? "" : ini_val;
    }
    field_total[0].value = index0;
    field_total[1].value = index1; 

    var button = document.getElementById('button');
    button.addEventListener("click", function(e){
        e.preventDefault();    
        all_total.value = index0 + index1;      
    }); 
});

※ class などでコードが煩雑になり、見やすさが悪くなってしまいそうでしたので CSS に関する要素とコードは省略してますので見た目は動画と異なります。

解説

では!コードの解説をしていきます!
まず前回のコードのイケてない部分を認識しましょう。

・値を1つずつ取得して計算しているため無駄に長い

これはただコードの見た目で言ってるわけではないです。
値を1つずつ取得するために行ごとに row1, row2 と連番をつけて識別させてましたがこんなこと言われたらどうしましょう?

「計算式の行をいっぱい追加してほしい。」

するとこんな手間が発生します。

・追加するごとに HTML コードに連番をつける手間
・追加するごとに JavaScript で1つずつ値を取得する手間

/(^o^)\ナンテコッタイ

結構めんどいと思いますw
コピペすればいいのですが、いちいち番号の部分だけ編集しなきゃいけないし、今何番目やってるんだっけ?とかなると思いますし、、

同じ処理の繰り返しなのにどんどん長くなるのは回避したいですよね。
なのでこんな風に改善するといいと思います。

・HTML 要素を一括で取得する
・計算はループで簡潔にする

これなら後から追加しても編集の工程が減ると思います。
では HTML 要素を一括で取得する方法からみていきましょう!

HTML 要素の一括取得

HTML 要素を一括で取得するのには命名規則にちょっと工夫してあげるといいです。
ですので変更点としては HTML コードの name に連番をつけてたところを class で名前を統一しちゃいましょう。

単価: name=”row1_price” → class=”price”

こんな感じで連番の部分を全部同じ名前の class に変更。
※詳細は添付してる HTML コードを参照してください。

ちなみに、もともと連番を使った理由は同じ名前の変数はどんどん新しい値に上書きされてしまうからです。

この考えがそもそも間違ってました。

変数名を一緒にしても配列にすればよかったのです。
では、配列の形式での要素の取得方法をみてみましょう。

querySelectorAll の使いかた

こんな便利なメソッドがあったみたいです!

Document.querySelectorAll()
Document の querySelectorAll() メソッドは、与えられた CSS セレクターに一致する文書中の要素のリストを示す静的な (生きていない) NodeList を返します。

これで指定した全ての要素を配列で取得してくれます。

「All」を抜いた querySelector でしたら指定した要素を1つ取得しますのでついでに一緒に覚えちゃいましょう。

まとめるとこんな感じです。

関数名 引数 戻り値
querySelector DOM String Element
querySelectorAll DOM String Node List

app.js ではこの部分で使ってます。

var price = document.querySelectorAll('.price');
var total = document.querySelectorAll('.total');
var traffic = document.querySelectorAll('.traffic'); 
var count = document.querySelectorAll('.count');
var field_total = document.querySelectorAll('.field_total');
var all_total = document.querySelector('input[name=all_total]');

ブラウザのコンソールで取得できてるか確認してみましょう。
var price = document.querySelectorAll(‘.price’); をそのままコンソールに貼り付け以下の結果が返っていることが確認できます。

NodeList(6) と縦一列の6つの要素が全て配列で取得できてます。
確実にこっちの方が楽ですね。

あとは同じように要素を取得して、おきまりの配列をループで回していけばいけそうな感じがしますね!

配列をループで取得する

ループは以下のように使用します。


for(var i = 0; i < 3; i++){
  index0 += (ini_val = parseInt(price[i].value || 0) * parseInt(traffic[i].value || 0));
  total[i].value = price[i].value == "" ? "" : ini_val;
  index1 += (ini_val = parseInt(price[i+3].value || 0) * parseInt(count[i].value || 0));
  total[i+3].value = price[i+3].value == "" ? "" : ini_val;
}

ループをテーブルの行数分回して、一つずつ配列に納める→入力値か空(0)のどちらかを条件分岐させて計算を行うという処理を繰り返しています。

ちなみにテキストボックスは合計6行で同じ class ですので6回ループしたいところですがセレクトボックスが3×2で別の class です。

それだと4行目からのセレクトボックスにループの値を保存しておく場所が無くなってしまいますね。

ですのでテキストボックスも同じく3×2の構成に分割するために price[i+3] のように記述しすることで3 + ループの回数になり、4,5,6行目のループをうまく回るようにするちょいテクも入ってます!

これならたとえ行数がふえてもループの回数を変更すれば大丈夫ですので後に変更があっても対応しやすいかと思います!

あとは計算で用いてる条件式について少しふれておきましょう!

短い条件式は三項演算子を使う

条件式といえば真っ先に思い浮かぶのって if 文ですよね。
ですが実は if 文は場合によってはプログラマーに嫌われがちだったりします。

とくに条件分岐を何回も繰り返してめっちゃネストした if 文とかドン引きされます。
合コンの最初の自己紹介でエグい下ネタぶちこむくらいにはドン引きされると思います。

ですので if 文の簡単な書き換えができる三項演算子を積極的に使っていきましょう!

・if 文の構文

if (条件式) {
  // 式1
} else {
  // 式2
}

・三項演算子の構文

条件式 ? 式1 : 式2 ;

明らかに簡潔に記述できるかと思います。

今回のコードでは以下の部分です。

・app.js

  index0 += (ini_val = parseInt(price[i].value || 0) * parseInt(traffic[i].value || 0));
  total[i].value = price[i].value == "" ? "" : ini_val;
  index1 += (ini_val = parseInt(price[i+3].value || 0) * parseInt(count[i].value || 0));
  total[i+3].value = price[i+3].value == "" ? "" : ini_val;

あとはテーブルごとの合計値である var field_total = document.querySelectorAll(‘.field_total’); にループの計算結果を代入

 field_total[0].value = index0;
 field_total[1].value = index1;

配列で要素を取得してますのでインデックスを指定すればテーブルごとの合計値を求められます。

最後に前回の記事と同じくイベントリスナーでボタンクリックをしたら総合計を求めるようにする。

var button = document.getElementById('button');
button.addEventListener("click", function(e){
    e.preventDefault();    
    all_total.value = index0 + index1;      
});

これで完成です。

おわりに

最後まで読んでいただきありがとうございます!

今回のはちょっとできた気分になれるプログラミングかとは思います。

あとは計算方法に parseInt を使用してますが、この関数ちょっと落とし穴があるのでそこら辺も改善案を考えてシェアしていきたいと思います。

次の記事では最後に HTML をほとんど使わないで同じアプリを作ってみようかと思います。
DOM 操作での HTML 要素生成の部分になります。

それで DOM 操作はだいぶ理解が深まるかと思います。

3回同じですがそれくらいよく使う機能だとは思いますので飽きずに最後までお付き合いいただけたらと思います!

それではまた!

スポンサーリンク
あっきー

元キャバクラ店長から未経験でエンジニアに転職した異端児。

「週4の5時間勤務、月収100万円」を実現させ、ゆるりと生きることを目標に日々パソコンと奮闘している。

自分の経験を元に、未経験からでも挫折しないプログラミングの勉強方法や最新技術や情報などを発信していきます。

あっきーをフォローする
HTML/CSSJavaScript
\良い記事だったらシェアしてね!/
スポンサーリンク
駆け出しエンジニアのつぶやき