原生JavaScript實現輕量級計算器


  想嘗試做一個網頁版計算器后,參考了很多博客大神的代碼,綜合歸納、總結修改,整理如下文。

  附:   Demo     源碼

 

一、HTML+CSS

  具體結構樣式如下圖,基本參照手機計算器界面。按鈕功能可以查看demo,都可以實現。

  

  這部分布局不是重點,只附上代碼以便理解JS行為。

  HTML/結構:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JS實現輕量級計算器</title>
    <link href="css/style.css" type="text/css" rel="stylesheet" />
    <script src="js/script.js" type="text/javascript" rel="stylesheet"></script>
</head>
<body>
<div id="box">
    <div id="top">
        <p>Lightweight Calculator by PYJ</p>
        <input id="screen0" type="text" style="margin-top: 100px;" disabled/>
        <input id="screen1" type="text" style="margin-top: 190px;" disabled/>
    </div>
    <div id="main">
        <span class="div1" style="font-size: 26px">(</span>
        <span class="div1" style="font-size: 26px">)</span>
        <span class="div1" style="font-size: 26px">DEL</span>
        <span class="div1">/</span>

        <span class="div2">7</span>
        <span class="div2">8</span>
        <span class="div2">9</span>
        <span class="div1">*</span>

        <span class="div2">4</span>
        <span class="div2">5</span>
        <span class="div2">6</span>
        <span class="div1">-</span>

        <span class="div2">1</span>
        <span class="div2">2</span>
        <span class="div2">3</span>
        <span class="div1">+</span>

        <span class="div2">0</span>
        <span class="div2">.</span>
        <span class="div1">C</span>
        <span class="div3" style="width: 94px;background: orangered;">=</span>
    </div>
</div>
</body>
</html>

   CSS/表現:

*{
    margin: 0;
    padding: 0;
    font-family: "Consolas", "Menlo", "Courier", monospace;
}
span{display: block;}
body{background: #f0f2f1;}

#box{
    width: 380px;
    height: 675px;
    margin-top: 8px;
    margin-left: auto;
    margin-right: auto;
    box-shadow:0 0 10px #888;
}

#top{
    width: inherit;
    height: 285px;
    background: #333333;
    position: relative;
}
#top p{
    color: #e7e7e7;
    font-size: 16px;
    padding-top: 5px;
    padding-right: 10px;
    text-align: right;
}
#top input{
    width: 368px;
    height: 70px;
    position: absolute;
    color: #e8e8e8;
    background: none;
    border: none;
    font-size: 35px;
    text-align: right;
    line-height: 70px;
    cursor: text;
    padding-right: 10px;
}

#main{
    width: inherit;
    height: 390px;
    background: #f0f2f1;
}
#main span{
    width: 94px;
    height: 77px;
    border-right: 1px solid #dff0d8;
    border-top: 1px solid #dff0d8;
    float: left;
    font-size: 32px;
    text-align: center;
    line-height: 80px;
    cursor: pointer;
}
.div1{color: orangered;}
.div2{color: #000;}
.div3{border-right: none;color: #fff;}

#main span:hover{background: #e1e1e1;}
#main span:active{box-shadow: 0 0 5px 5px #fff;}

 

二、JavaScript/行為

  行為層要解決的問題大致可以總結為:獲取被點擊的按鈕內容,給出相應反應或組成表達式;計算表達式並顯示。

1. 初始化(清屏):

1 window.onload = function(){
2     var screen0 = document.getElementById('screen0'),   //獲取上顯示器內容
3         screen1 = document.getElementById('screen1');   //獲取下顯示器內容
4     screen0.value = null;
5     screen1.value = null;
6     calculate(screen0, screen1);     
7 };

 

2. 上面代碼最后一行調用了calculate()函數,獲取按鈕字符:

 1 function calculate(screen0,screen1){
 2     var box = document.getElementById('main'), //獲取按鈕盒子
 3         count = 0;                             //記錄顯示器字符或數字個數
 4 
 5     box.onclick = function(e){
 6         var symbol = e.target.innerText;       //獲取按鈕字符
 7 
 8         //內容是否超過允許長度
 9         if((screen1.value + symbol).length > 40){
10             alert('Content exceeds the maximum length!');
11             return null;
12         }
13         if(symbol == 'C' ){          //清零
14             count = 0;
15             screen0.value = null;
16             screen1.value = null;
17         }else if(symbol != '='){     //表達式
18             if(count == -1){         //對上一次計算的清空
19                 screen0.value += "=" + screen1.value;
20                 screen1.value = symbol;
21                 count = 1;
22             }else if(symbol == 'DEL'){
23                 if(screen1.value == null){
24                     count = 0;
25                 }else{
26                     screen1.value = screen1.value.slice(0,-1);
27                     count--;
28                 }
29             }else{
30                 screen1.value += symbol;
31             }
32         }else if(symbol == '='){    //計算結果
33             screen0.value = screen1.value;
34             screen1.value = test(screen1.value );
35             count = -1;
36         }
37     }
38 }

   分別對清零、回刪、“=”和其他字符情況做出判斷,給予不同的處理結果。

 

3. 按了“=”,就表示要對前面的字符串進行計算了:

  但在計算前,需要了解一下JS數字精度丟失的問題。計算機的二進制的實現和位數限制會使部分數無法有限表示,有窮的數在計算機的二進制里卻是無窮的,因存儲位數的限制而發生的“舍去”,就導致了精度的丟失。具體內容不再展開,可以去查看相關文檔。

  為了解決浮點數的精度丟失問題,在這里為Math對象定義了一個方法:

1 Math.formatFloat = function (exp, digit){
2     var m = Math.pow(10, digit);
3     return parseInt(exp*m, 10)/m;
4 };
5     //把小數放到位整數(乘倍數),再縮小回原來倍數(除倍數)

  

  計算器最核心的算法就是表達式的運算。

  本文的思想是,將表達式按符號拆分並運用遞歸:

 1 function test(text) {
 2     var index = 0;   //記錄符號索引
 3 
 4     while(text){
 5         //首先計算括號內內容
 6         if(text.lastIndexOf("(") > -1){
 7             index = text.lastIndexOf("(");
 8             var endIndex = text.indexOf(")", index);
 9             if(endIndex > -1) {
10                 var result = Math.formatFloat(test(text.substring(index + 1, endIndex)) ,2);
11                 return Math.formatFloat(test(text.substring(0, index) + result + text.substring(endIndex + 1)) ,2);
12             }
13 
14         }else if(text.indexOf("+") >-1){
15             index = text.indexOf("+");
16             return Math.formatFloat(test(text.substring(0, index)) + test(text.substring(index + 1)) ,2);
17 
18         }else if(text.lastIndexOf("-") > -1){
19             index = text.lastIndexOf("-");
20             if(text[index-1] == '*'){
21                 return Math.formatFloat(test(text.substring(0, index-1)) * test(text.substring(index)) ,2);
22             }else if(text[index-1] == '/'){
23                 return Math.formatFloat(test(text.substring(0, index-1)) / test(text.substring(index)) ,2);
24             }else{
25                 return Math.formatFloat(test(text.substring(0, index)) - test(text.substring(index + 1)) ,2);
26             }
27 
28         }else if(text.lastIndexOf("*") > -1){
29                 index = text.lastIndexOf("*");
30             return Math.formatFloat(test(text.substring(0, index)) * test(text.substring(index + 1)) ,2);
31 
32         }else if(text.lastIndexOf("/") > -1){
33             index = text.lastIndexOf("/");
34             return Math.formatFloat(test(text.substring(0, index)) / test(text.substring(index + 1)) ,2);
35 
36         }else{
37             return Math.formatFloat(text,2);
38         }
39     }
40 
41     return null;
42 }

  需要注意:首先對括號內內容進行運算;“-” 號和除號要從表達式尾部開始提取,否則計算有誤;“-” 號有負號和減號之分,解決辦法是,在 “-” 號前有乘號和除號時,要按乘號或除號拆分;Math.formatFloat() 方法的運用。

 


 使用效果圖如下,存在bug或者文中有錯誤的話希望指出 [抱拳]

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM