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

Javascriptで電卓を作ろう。初心者向けです。
# 目次
[第1回 HTMLとCSSでボタンを横並びで配置しよう](https://qiita.com/rikimaru914/items/3412df78570b48b25858)

- HTMLのマークアップ
- CSS

[第2回　四則演算をやってみよう](https://qiita.com/rikimaru914/items/a30d83c43a4eb14ba999)

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

[第3回　連続で演算記号や小数点が押された場合の不具合処理](https://qiita.com/rikimaru914/items/8df2124165afd036b922)

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

[第4回　小数点を正しく入力できるように改善しよう](https://qiita.com/rikimaru914/items/61154567fa02f1d7a156)

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

[第5回　演算記号を連続して押した時の不具合を直そう](https://qiita.com/rikimaru914/items/21b3e4532f0de41db9a6)

[第6回　バックスペースを押した時の不具合を直そう](https://qiita.com/rikimaru914/items/0a97bfa685620f16cd5b)

[第7回　「4 ÷ 3 = 1.33333333333333333」の表示桁数を10桁にしたい](https://qiita.com/rikimaru914/items/c3f23aa65f4be780d6ff)

[第8回　「電卓と同じ表示画面を目指そう（今回の記事はここ）](https://qiita.com/rikimaru914/items/b4076b2673014034076c)

#今回やりたいこと
「5×8」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320736/7d6434a2-9aaa-73a9-a939-73095d7d8caa.png)
「＝」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320736/53f8fda4-e115-41c5-3a5b-b2d98b04e8b8.png)
このようにしたい。

現在、表示箇所が二か所あります。計算の途中の結果が見やすいようにあえてそうしていましたが、実際の電卓と同じように、
計算中：計算過程画面
計算後：計算結果画面
が表示されるように変更します。

###考え方
表示画面にclass="active"を付ける。
計算中：計算過程画面activeを付ける、計算結果画面activeを外す
計算後（=を押したら）：計算過程画面activeを外す、計算結果画面activeを付ける。
class="active"がある場合、display:block;
class="active"がない場合、display:none;
とCSSですればよい。

最初：計算過程active
計算中：計算過程active
＝を押した時：計算結果active
そのあと記号、数字、小数点、0を押した時：計算過程active


###HTML

```html
<!--      計算結果を出力する場所-->
      <div id = "output_total" class="output ">0</div>
<!--      計算過程を出力する -->
      <div id = "output_sub" class="output active">0</div>

```

###CSS

```css

.output {
  width: 200px;
  height: 50px;
  line-height: 50px;
  text-align: right;
  padding: 5px;
  margin-bottom: 5px;
  border:2px solid black;
  box-sizing: border-box;
  display:none;
}

.output.active {
  display:block;
}

```

###Javascript

```javascript
 //計算過程結果、計算結果画面の表示の切り替え
  //  「=」を押した後、 計算後state==='finish'の時だけ計算結果画面output_totalにclass="active"を付ける。そのほかの時はその逆にする。
  function changeOutput(){
    if(state==='finish'){
      output_total.classList.add('active');
      output_sub.classList.remove('active');   
    }else{
      output_sub.classList.add('active');
      output_total.classList.remove('active'); 
    } 
  }
```

#完成したコード

###HTML

```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>


```

###CSS

```css

.container {
  width: 200px;
  margin: 50px auto;
  border: 2px solid black;
}

.output {
  width: 200px;
  height: 50px;
  line-height: 50px;
  text-align: right;
  padding: 5px;
  margin-bottom: 5px;
  border:2px solid black;
  box-sizing: border-box;
  display:none;
}

.output.active {
  display:block;
} 

.input {
  width:200px;
  border: 2px solid black; 
}

.row {
  display: flex;
  justify-content: space-between;
  border: 2px solid red;
  width: 200px;
}
/*rowの範囲がわかりやすいように赤の枠を作っています。*/

.num_bth, #clear, #equal_btn{
  width: 60px;
  height: 30px;
  text-align: center;
  line-height: 30px;
  border-radius: 30%;
  background: lightgray;
  cursor: pointer;
  margin: 5px;
}


```

###Javascript

```javascript
'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';//最初の状態を定義
    //  1)計算する前の最初の状態（start）　
    //  2)数字を入力している最中（calculation）
    //  3)「＋　÷　－　×　＝」を押した直後（calBtn）
    //  4)「＝」を教えて計算が終わった直後（finish）
    //  変数stateに、star,calculation, calBtn, finishを代入して状態を管理します。  
  let mode = 'integer_mode'; //最初は整数入力モード
  //  変数modeに、整数入力中integer_mode、小数入力中decimal_modeを定義します。
  
  // 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'||state === 'calBtn'){
          //計算中totalに打った数字を追加して、totalに代入する。
          total += index.dataset.indexId;
        }     
        output_sub.textContent = total;
        state = 'calculation'//数字を入力している状態にする。
        changeOutput()//計算結果・計算過程画面の入れ替える
      }) //click   
    })//forEach
  
  // 0の数字ボタンを押した時
  const zero = document.getElementById('zero');
  zero.addEventListener('click', () => {
//    - 最初state==='start
//    - 計算終了後state==='finish'
//    - 演算記号入力直後state==='calBtn'の時、
//    前の文字が0の時は0が入力できないようにする。
  if(state==='start'||state==='finish'||state==='calBtn'){
      if(output_sub.textContent.slice(-1) === '0') {
        //sliceで切り出されたのは0ではなく'0'
        console.log('前の文字はゼロ');
        return;
      }
    }
    
    if(state==='start') {
      total = zero.dataset.indexId;  
    }else{
      total += zero.dataset.indexId;
    }      
    output_sub.textContent = total;
    changeOutput()//計算結果・計算過程画面の入れ替える
//    state = 'calculation'//数字を入力している状態にする。
  }) //click    
  
  // 「.」小数点ボタンを押した時
  const point = document.getElementById('point');
  point.addEventListener('click', () => {
    console.log(point.dataset.indexId)
    if(mode === 'decimal_mode'){
      return; //小数点入力モードではもう一度小数点を押せない
       }      
    //「.4」と入力したら0.4としたい。(1)+(2)で0.4となる
    if(state==='start'||state==='finish') {
      total = 0;//(1)最初と計算終了直後なら、0を入力
    }else if(state==='calBtn'){
      //これを入れないと、0.4+0.4と打つと0.4+00.4となる。
      if(output_sub.textContent.slice(-1)!=='0'){
        total += 0;//(1')演算記号入力直後なら、今までの計算結果に0を入力
      }   
    }
    total += point.dataset.indexId;//(2)「.」を入力
    
    output_sub.textContent = total;
    state = 'calculation'//数字を入力している状態にする。
    mode = 'decimal_mode'; //小数入力モードに変更
    changeOutput()//計算結果・計算過程画面の入れ替える
  }) //click  
  
  //「＋　÷　－　×」ボタンを押した時
  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
      }else if(state ==='calBtn') {
        // 演算記号入力状態state = 'calBtn'の時に、演算記号を押したら、totalの最後の一文字（演算記号）を削除し、新たに押した演算記号を追加する。
//        →totalに、totalの最初から最後から二文字目までを代入する（最後の一文字を削除する）
        total = total.slice(0, -1)
        total += index.dataset.indexId;
      }
      
      output_sub.textContent = total;
      state = 'calBtn'//演算記号を入力している状態する。
      mode ='integer_mode'//整数モードに戻す
      changeOutput()//計算結果・計算過程画面の入れ替える
    }) //click   
  })//forEach
  
  //イコールを押した時
  const equal_btn = document.getElementById('equal_btn');
  equal_btn.addEventListener('click',() =>{
    console.log(eval(total));
    output_total.textContent = digitNum(eval(total));//桁数を揃える関数10桁を表示させる関数digitNum
    state = 'finish'//計算が終わった状態にする。
    mode ='integer_mode'//整数モードに戻す
    changeOutput()//計算結果・計算過程画面の入れ替える
  });

  //Cボタン（リセットボタン）を押した時の処理
  const clear = document.getElementById('clear')
  clear.addEventListener('click', () => {
    reset();
  })
  
 //リセットを行う関数
  function reset() {
    total = 0; 
    output_sub.textContent = 0;
    output_total.textContent = 0;
    mode ='integer_mode'//整数モードに戻す
    state ='start';
    changeOutput()//計算結果・計算過程画面の入れ替える
  }
  
  //BSボタン（バックスペース）を押した時の処理
  const bs = document.getElementById('bs')
  bs.addEventListener('click', () => {
    if(state ==='finish') {
      return;//計算後は、bsを押せない。
    }
//      一文字目から、最後から二文字目までをtotalに代入（最後の一文字を除きtotalに代入する）     
    total = output_sub.textContent.slice(0, -1);
    output_sub.textContent = total;
    
    let lastWord = output_sub.textContent.slice(-1)
    if(lastWord==='+'||lastWord==='-'||lastWord==='*'||lastWord==='/') {
//bsを押し、最後の文字が演算記号ならstateを演算記号入力中calBtに変更
      state = 'calBtn'
    }else if(lastWord==='') {
//bsを押し、文字が空ならstateを最初startに変更
      state = 'start';
    }    
  });
  
  //桁数を揃える関数10桁を表示させる関数
  function digitNum(num) {
    return Math.round(num*100000000)/100000000;
  }
  
  //計算過程結果、計算結果画面の表示の切り替え
  //  「=」を押した後、 計算後state==='finish'の時だけ計算結果画面output_totalにclass="active"を付ける。そのほかの時はその逆にする。
  function changeOutput(){
    if(state==='finish'){
      output_total.classList.add('active');
      output_sub.classList.remove('active');   
    }else{
      output_sub.classList.add('active');
      output_total.classList.remove('active'); 
    } 
  }

}

```

これで一応不具合の修正等はできたと思っています。
もし、やっている中で不具合等見つけたら、ご一報ください。
頑張って考えます！！

それにしても電卓というのは、本当に勉強になりますね。
いろんな基礎的な要素がいっぱいです。

ぜひ、皆さんの作った電卓のコードも紹介してください。
情報交換できたらうれしいです。
ご連絡お待ちしています。