2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Javascriptで電卓を作ろう 第3回 連続で演算記号や小数点が押された場合の処理

Last updated at Posted at 2019-05-28

目次

第1回 HTMLとCSSでボタンを横並びで配置しよう

  • HTMLのマークアップ
  • CSS

第2回 四則演算をやってみよう

  • Javascriptで四則演算
  • 6)打った数字をコンソールに出力させよう。
  • 7)打った数字と記号を変数に格納しよう。
  • 8)計算結果を出力させよう。
  • 8-1)「=」を押した時の処理
  • 8-2) 計算結果と計算途中を、計算結果の画面に表示させよう。

第3回 連続で演算記号や小数点が押された場合の不具合処理(今回の記事はここ)

  • 最初に「+ ÷ - × =」が押せないようにする。
  • 二回連続で計算できるようにしたい。
  • Cボタン(リセットボタン)を押した時の処理
  • BS(バックスペース)ボタンを使えるようにする

第4回 小数点を正しく入力できるように改善しよう

  • 12.12.や12..12のように小数点を間違って入力できてしまう。
  • 電卓と同じように「.4」と入力したら0.4としたい。

第5回 演算記号を連続して押した時の不具合を直そう

第6回 バックスペースを押した時の不具合を直そう。

第7回 「4 ÷ 3 = 1.33333333333333333」の表示桁数を10桁にしたい

第8回 「電卓と同じ表示画面を目指そう

前回作成した電卓について、以下のような点を改善したいと思います。
前回の記事

  • 最初に「+ ÷ - = .」が押せてしまう。
  • 最初に0を連続で押せてしまう(00.4や00043となってしまう)
  • 記号ボタン(+×÷-)を連続で押せてしまい、計算ができない。(連続で押した場合は、最後に押した記号ボタンが採用されるようにしたい。
  • 一度計算をやると、次の計算をするときに、ブラウザを読み込みなおさないといけない(Cボタンを使えるようにしよう)
  • 前回の計算結果を利用して、次の計算を行いたい。
  • 12.12.や12..12のように間違った小数を入力できてしまう。
  • 電卓と同じように「.4」と入力したら0.4としたい。
  • 一度間違えると、全てやり直し(BSボタンを使えるようにしたい)
  • 割り算等で小数点以下が異様に長い。

#対処法1)
これらに対応するため、状態を定義します。
1)計算する前の最初の状態(start) 
2)数字を入力している最中(calculation)
3)「+ ÷ - × =」を押した直後(calBtn)
4)「=」を教えて計算が終わった直後(finish)
stateという変数を用意して、star,calculation, calBtn, finishを代入して状態を管理します。

1)計算する前の最初の状態(start) 

  • 「+ ÷ - × =」が押せないようにする。
  • 0を連続で押された時に、1つだけ入力するようにしたい。

2)数字を入力している最中(calculation)

  • どのボタンも押せる

3)「+ ÷ - ×」を押した直後(calBtn)

  • 「+ ÷ - ×」を連続で押した場合、最後に押されたボタンを採用するようにしたい。
  • 0を連続で押された時に、1つだけ入力するようにしたい。

4)「=」を教えて計算が終わった直後(finish)

  • 「=」を押せないようにしたい。
  • 次に数字が押された場合、前の計算結果はリセットして、計算をやり直す。
  • 次に「+ ÷ - ×」を押した場合、前回の計算結果を利用して続けて計算する。

#対処法2)
これとは別に整数入力中、小数入力中を別の変数で定義します。
modeという変数を用意して、integer_mode、decimal_modeを代入して状態を管理します。
a)整数入力中(integer_mode)

-「.」小数点を押すことができる。

b)小数入力中(decimal_mode)

- 「+ ÷ - ×」が押されるまでは、「.」小数点を押すことができない。(12.12.4や12..12とならないようにしたい)

#HTMLの変更
現在は、0,1,2,3,4,5,6,7,8,9,+,-,,/全てが同じclass="num_bth"となっているが、状態管理するにあたり、「0」「1-9」「+,-,,/」「.(point)」を別の変数で管理することにします。
「0」 id="zero"
「1-9 class="one_nine"
「+,-,*,/」class="cal"
「. (point)」 id="point"

HTML変更後

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>電卓</title>
    <link rel="stylesheet" href="style.css">
  </head>
  <body>
    <div class = "container">
<!--      計算結果を出力する場所-->
      <div id = "output_total" class="output ">0</div>
<!--      計算過程を出力する -->
      <div id = "output_sub" class="output active">0</div>
<!--      ボタンを配置する場所-->
      <div class = 'input'>
          <section class = 'row'>
            <div id = "clear">C</div>
            <div class = "num_bth"></div>
            <div class = "num_bth" id="bs">BS</div>       
            <div class = "num_bth cal" data-index-id= '/'>÷</div>
          </section>
          <section class = 'row'>
            <div class = "num_bth one_nine " data-index-id = 9 >9</div>
            <div class = "num_bth one_nine " data-index-id = 8 >8</div>
            <div class = "num_bth one_nine " data-index-id = 7 >7</div>
            <div class = "num_bth cal" data-index-id = '*'>×</div>
          </section>
          <section class = 'row'>
            <div class = "num_bth one_nine " data-index-id = 6 >6</div>
            <div class = "num_bth one_nine " data-index-id = 5 >5</div>
            <div class = "num_bth one_nine " data-index-id = 4 >4</div>
            <div class = "num_bth cal" data-index-id = '-'></div>     
          </section>
          <section class = 'row'>
            <div class = "num_bth one_nine " data-index-id = 3 >3</div>
            <div class = "num_bth  one_nine" data-index-id = 2 >2</div>
            <div class = "num_bth  one_nine" data-index-id = 1 >1</div>
            <div class = "num_bth cal" data-index-id = '+'>+</div>
          </section>
          <section class = 'row'>
            <div class = "num_bth" data-index-id = 00 >00</div>
            <div class = "num_bth" id="zero" data-index-id = 0 >0</div>
            <div class = "num_bth" id="point" data-index-id = . >.</div>
            <div id = 'equal_btn'>=</div>       
          </section>        
      </div>
    </div>
    <script src="script.js"></script>
  </body>
</html>

#JavascriptをHTMLに合わせて、「0」「1-9」「+,-,*,/」「.(point)」が押せるように以下のように変更

'use strict'
{
  const num_bth = document.querySelectorAll('.num_bth');
  let output_sub = document.getElementById('output_sub');//計算結果を表示する場所
  const output_total = document.getElementById('output_total');//計算過程を表示する場所
  let total = 0;//計算式を表す変数 
  let state = 'start';//最初の状態を定義
  let mode = 'integer_mode'; //最初は整数入力モード
  
  // 1-9の数字ボタンを押した時
    const one_nine = document.querySelectorAll('.one_nine');
    one_nine.forEach(index => {     
      index.addEventListener('click', () => {
        console.log(index.dataset.indexId)
        if(total === 0) {
          total = index.dataset.indexId;  
        }else{
          total += index.dataset.indexId;
        }      
        output_sub.textContent = total;
        state = 'calculation'//数字を入力している状態にする。
      }) //click   
    })//forEach
  
  // 0の数字ボタンを押した時
  const zero = document.getElementById('zero');
  zero.addEventListener('click', () => {
    console.log(zero.dataset.indexId)
    if(total === 0) {
      total = zero.dataset.indexId;  
    }else{
      total += zero.dataset.indexId;
    }      
    output_sub.textContent = total;
    state = 'calculation'//数字を入力している状態にする。
  }) //click    
  
  // 「.」小数点ボタンを押した時
  const point = document.getElementById('point');
  point.addEventListener('click', () => {
    console.log(point.dataset.indexId)
    if(total === 0) {
      total = point.dataset.indexId;  
    }else{
      total += point.dataset.indexId;
    }      
    output_sub.textContent = total;
    state = 'calculation'//数字を入力している状態にする。
    mode = 'decimal_mode'; //小数入力モードに変更
  }) //click  
  
  //「+ ÷ - ×」ボタンを押した時
  const cal = document.querySelectorAll('.cal');
  cal.forEach(index => {     
    index.addEventListener('click', () => {
      console.log(index.dataset.indexId)
      if(total === 0) {
        total = index.dataset.indexId;  
      }else{
        total += index.dataset.indexId;
      }      
      output_sub.textContent = total;
      state = 'calBtn'//演算記号を入力している状態する。
    }) //click   
  })//forEach
  
  //イコールを押した時
  const equal_btn = document.getElementById('equal_btn');
  equal_btn.addEventListener('click',() =>{
    console.log(eval(total));
    output_total.textContent = eval(total);
  });
  
}

#最初に「+ ÷ - × =」が押せないようにする。
最初の状態の時state==='start'に演算記号が押せないようにしたい。

  if(state === 'start') {
        return;
      }

returnとし、以下の処理が行われないようにすればよい。

  //「+ ÷ - ×」ボタンを押した時
  const cal = document.querySelectorAll('.cal');
  cal.forEach(index => {     
    index.addEventListener('click', () => {
      if(state === 'start') {
        return;
      }
      console.log(index.dataset.indexId)
      if(total === 0) {
        total = index.dataset.indexId;  
      }else{
        total += index.dataset.indexId;
      }      
      output_sub.textContent = total;
      state = 'calBtn'//演算記号を入力している状態する。
    }) //click   
  })//forEach

#二回連続で計算できるようにしたい。
「2 × 3 = 6」「6 + 2 = 8」を連続して計算しようとするとこうなってしまう
image.png
電卓の機能として以下のようにしたい。

  • 計算後に数字を押した場合:前回の結果はリセットして計算しなおす。
  • 計算後に演算記号を押した場合:前回の計算結果にを再度利用して計算を続ける。

というわけで、数字を押した時、記号を押した時の各stateごとの処理は以下の通り。
数字を押した時

  • 最初(state==="start"):
    • totalに打った数字を代入する
    • stateをcalculationに変える
  • 計算後(state==="finish")
    • リセット処理後に、totalに打った数字を代入する
    • stateを計算中(calculation)に変える
  • 計算中(state==="calculation")
    • totalに打った数字を追加して、totalに代入する。
  // 1-9の数字ボタンを押した時
    const one_nine = document.querySelectorAll('.one_nine');
    one_nine.forEach(index => {     
      index.addEventListener('click', () => {
        if(state === 'start') {
          //最初totalに打った数字を代入する
          total = index.dataset.indexId;         
        }else if(state === 'finish') {
          //計算後、リセット処理後に、totalに打った数字を代入する
          reset();
          total = index.dataset.indexId;  
        }else if(state === 'calculation'){
          //計算中totalに打った数字を追加して、totalに代入する。
          total += index.dataset.indexId;
        }     
        output_sub.textContent = total;
        state = 'calculation'//数字を入力している状態にする。
      }) //click   
    })//forEach


//リセットを行う関数
  function reset() {
   total = 0; 
   output_sub.textContent = 0;
   output_total.textContent = 0;
  }

記号を押した時

  • 最初(state="start"):
    • 記号は押せないようにする
  • 計算後(state="finish")
    • 前の計算結果をtotal に代入して計算しなおす。
    • 計算過程表示画面に前の計算結果を表示させる。
    • 計算結果表示画面を"0"を表示させる。
    • stateを演算記号を押した後(calBtn)に変える
  • 計算中(state="calculation")
    • totalに打った記号を追加し、totalに代入する。
      • stateを演算記号を押した後(calBtn)に変える
  //「+ ÷ - ×」ボタンを押した時
  const cal = document.querySelectorAll('.cal');
  cal.forEach(index => {     
    index.addEventListener('click', () => {
      if(state === 'start') {
        return;//最初記号は押せない
      }else if(state === 'calculation'){
        total += index.dataset.indexId;//計算中はtotalに打った記号を追加し、totalに代入する。
      }else if(state === 'finish'){
        //計算後は前の計算結果をtotal に代入して計算しなおす。
        total = output_total.textContent;
        total += index.dataset.indexId;
        output_total.textContent = 0
      }
      console.log(index.dataset.indexId)   
      output_sub.textContent = total;
      state = 'calBtn'//演算記号を入力している状態する。
    }) //click   
  })//forEach

#Cボタン(リセットボタン)を押した時の処理

  //Cボタン(リセットボタン)を押した時の処理
  const clear = document.getElementById('clear')
  clear.addEventListener('click', () => {
    reset();
  })
  
 //リセットを行う関数
  function reset() {
   total = 0; 
   output_sub.textContent = 0;
   output_total.textContent = 0;
  }

#BS(バックスペース)ボタンを使えるようにする

  • 計算終了後(state === "finish") はBSを押せない。
  • それ以外の時は、最初から最後から二文字目までをtotalに代入(最後の一文字を除きtotalに代入する)

slice関数
str.slice(0, -1) は、文字列から 0 番目の文字から最後から 2 番目の文字までを取り出します。
String​.prototype​.slice()

  //BSボタン(バックスペース)を押した時の処理
  const bs = document.getElementById('bs')
  bs.addEventListener('click', () => {
    console.log('BS')
    if(state ==="finish") {
      return;//計算後は、bsを押せない。
    }else{
//      一文字目から、最後から二文字目までをtotalに代入(最後の一文字を除きtotalに代入する)
      total = output_sub.textContent.slice(0, -1);
      output_sub.textContent = total;
    }
  })

#残りの課題 次回へ
- 最初に「+ ÷ - = .」が押せてしまう。

  • 最初に0を連続で押せてしまう(00.4や00043となってしまう)
  • 記号ボタン(+×÷-)を連続で押せてしまい、計算ができない。(連続で押した場合は、最後に押した記号ボタンが採用されるようにしたい。
    - 一度計算をやると、次の計算をするときに、ブラウザを読み込みなおさないといけない(Cボタンを使えるようにしよう)
    - 前回の計算結果を利用して、次の計算を行いたい。
  • 12.12.や12..12のように間違った小数を入力できてしまう。
  • 電卓と同じように「.4」と入力したら0.4としたい。
    - 一度間違えると、全てやり直し(BSボタンを使えるようにしたい)
  • 割り算等で小数点以下が異様に長い。
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?