0
3

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.

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

Last updated at Posted at 2019-06-04

Javascriptで電卓を作ろう。初心者向けです。

目次

第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回 「電卓と同じ表示画面を目指そう(今回の記事はここ)

#今回やりたいこと
「5×8」
image.png
「=」
image.png
このようにしたい。

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

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

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

###HTML

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

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

 //計算過程結果、計算結果画面の表示の切り替え
  //  「=」を押した後、 計算後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

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


.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

'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'); 
    } 
  }

}

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

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

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

0
3
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
0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?