一、前端样式部分

首先我们需要给计算机来写一个外壳,我们使用html和css来实现计算器的样子:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <style>
            #outbox{/*計算機底座 */
                width: 388px;
                height: 450px; 
                border: 0px;
                background-color: rgb(117, 174, 184);
                position: relative; /*对于父级元素的移动 */
            }
            
            #in_put{  /*輸入底座 */
                background-color: white; 
                width: 350px;
                height: 100px;
                display:inline-block;
                position: relative;
                left: 19px; 
                top: 10px;
            }

            #input_box{    /*輸入框 */
               height: 30px;
               left: 20px;
               font-size: 15px;
               /*background-color: rgb(199, 184, 187);*/
               position: absolute;
            }

            #out_box{       /*輸出框 */
                height: 30px;
                width: 100px;
                left: 250px;
                top: 30px;
                color: rgb(45, 188, 255);
                font-size: 30px;
                /* background-color: rgb(199, 184, 187); */
                position: absolute;
            }

            .inbox_1{
                height: 50px;
                width: 357px; 
                /*background-color: rgb(71, 136, 161);*/ 
                display: block;
                position: relative;
                left: 19px;
                margin-top: 20px;
            }
            .inbox_2{  /*按鍵底座 */
                height: 50px;
                width: 265px; 
                /*background-color: rgb(71, 136, 161); */
                display: block;
                position: relative;
                left: 19px;
                margin-top: 5px;
            }
            .ininbox{  /*按鍵框 */
                width: 84px;
                height: 35px;
                background-color: rgb(196, 139, 146);
                display: inline-block;  /*???問豆豆*/
                position: relative;    
                left: 0px;
                top: 2px;
                text-align: center; /*控制字体*/
                padding-top: 10px; /*控制字体*/
            }
            
            

        </style>
    </head>
    <body>
        <div id="outbox" >
            
            <div id="in_put">
                <p id="input_box"></p>
                <p id="out_box"></p>
            </div>

            <div class="inbox_1">    
                <div class="ininbox" id="add" onclick="submit(add.innerHTML)">+</div>
                <div class="ininbox" id="cut" onclick="submit(cut.innerHTML)">-</div>
                <div class="ininbox" id="mult" onclick="submit(mult.innerHTML)">*</div>
                <div class="ininbox" id="divi" onclick="submit(divi.innerHTML)">/</div>
            </div>
            <div onclick="show()" style="height: 111px; width: 85px; background-color: rgb(196, 139, 146); position:absolute;right: 18px; top: 180px;text-align: center;padding-top: 100px; ">
                =
            </div>
            <div class="inbox_2">
                <div class="ininbox" id="seven" onclick="submit(seven.innerHTML)">7</div>
                <div class="ininbox" id="eight" onclick="submit(eight.innerHTML)">8</div>
                <div class="ininbox" id="nine" onclick="submit(nine.innerHTML)">9</div>
                
            </div>
            <div class="inbox_2">
                <div class="ininbox" id="four" onclick="submit(four.innerHTML)">4</div>
                <div class="ininbox" id="five" onclick="submit(five.innerHTML)">5</div>
                <div class="ininbox" id="six" onclick="submit(six.innerHTML)">6</div>
            </div>
            <div class="inbox_2">
                <div class="ininbox" id="three" onclick="submit(three.innerHTML)">3</div>
                <div class="ininbox" id="two" onclick="submit(two.innerHTML)">2</div>
                <div class="ininbox" id="one" onclick="submit(one.innerHTML)">1</div>
            </div>
            <div class="inbox_2">
                <div class="ininbox" id="zero" onclick="submit(zero.innerHTML)" style="width: 172px;">0</div>
                <div class="ininbox" id="node" onclick="submit(node.innerHTML)">.</div>
            </div>

            <div onclick="get_empty()" style="height: 30px; width: 85px; background-color: rgb(245, 27, 52); position:absolute;right: 18px; top: 400px;text-align: center;padding-top: 10px; ">
                c
            </div>
        </div>
    </body>
</html>


对于外部的整体框架来说,我将整个计算器分成了这样的几个部分:

  • 整体计算机框架 :id = “outbox”
  • 显示框(显示数字输入结果和计算结果):id = “in_put”
  • 四个按键底座(包括 符号和数字,除了等于号和清零之外。因为等于和清理实现的不是输入操作)class = "inbox_1 " 、 class = “inbox_2”
  • 十三个按键 class = “ininbox”
  • 一个等于按钮
  • 一个清空按钮

对于整体的布局来说:

  • outbox、in_put、inbox1、inbox2、均为relative,让外部的框架处于文档流中从而自伤向下。

  • 在in_put中的input_box和out_box使用absolute定位这样,input_box和out_box会对他们的父级元素(in_put)产生偏移量去确定位置。

  • 对于ininbox来说他处于父级元素inbox中,inbox是一个postion属性为relative的元素,如果我们用absolute去给ininbox定位,我们必须去设置每一个ininbox的位置。这样太过繁琐。所以我们使用将ininbox的display属性设置为inline-block,这样我们的每一个案件既可以共同存在于一行,也可以为他去设置宽度。(如果是inline是不可以直接设置行宽的)

  • 对于等于号和清零键来说我们直接设置他的position为absolute就可以啦,这样他们针对于他们的父级元素outbox就是浮动的了,我们可以对他相对于他的父级元素来进行定位,这样比较方便。

二、再给元素加上我们喜欢的颜色和边距,这样我们就得到了一个完整的计算机的样式了




二、js逻辑部分

我们有了界面之后就可以去实现我们的计算器了。这个计算机没有括号。但是,是实现了乘除优先于加减的算法。

<script>
            let str = new Array();
            let strbefore = '';
            let stack_num = new Array();
            let stack_mark = new Array();
            let box = new Array();
            let len_str = 0;
            let len_num = 0;
            let len_mark = 0;
            let result = 0;

            function submit( symbol ){
                //alert(symbol);
                strbefore += symbol;
                input_box.innerHTML = strbefore;
                //console.log(len_str);
            }//接收表达式

            function get_empty(){
                out_box.innerHTML = '';
                input_box.innerHTML = '';
                str.length = 0;
                strbefore = '';
                stack_num.length = 0;
                stack_mark.length = 0;
                len_str = 0;
                len_num = 0;
                len_mark = 0;
                result = 0;
                //alert(str[0]);   
            }
            
            function show(){
                // for(let i = 0;i<=str.length;i++){
                //     console.log(str[i]);
                // }//检查传过来的数组是否正确
                for(let i = 0,j = 0;i < strbefore.length;i++){
                    if(strbefore[i] == '+' || strbefore[i] == '-' || strbefore[i] == '*' || strbefore[i] == '/'){
                        str[j] = strbefore[i];
                        j++;
                    }
                    else{
                         let num = '';
                        let flag = 0;
                        for(let k = i;strbefore[k] != '+' && strbefore[k] != '-' && strbefore[k] != '*' && strbefore[k] != '/' && k < strbefore.length;k++){
                            num += strbefore[k];
                            flag++;
                            // console.log(num);
                        }
                        flag--;
                        i = i + flag;
                        str[j] = parseFloat(num);
                        j++;
                    }
                }
                //处理传来的字符换构成可以计算的数组表达式

                for(let i = 0;i<=str.length;i++){
                    if(str[i] == '+' || str[i] == '-' ){
                        stack_mark[len_mark] = str[i];
                        len_mark++;
                    }
                    else if(str[i] == '*' || str[i] == '/' ){
                        let a,b,c;
                        a = stack_num[stack_num.length - 1];
                        b = str[i+1];
                        if(str[i] == '*'){
                            c = a * b;
                            stack_num[len_num - 1] = c;
                            i++;
                        }
                        if(str[i] == '/'){
                            c = a * b;
                            stack_num[len_num - 1] = c;
                            i++;
                        }
                    }
                    else{
                        stack_num[len_num] = str[i];
                        len_num++;
                    }
                }
            
                for(let j = 0;j<stack_num.length;j++){
                    console.log(stack_num[j]);
                }

                for(let k = 0;k<stack_mark.length;k++){//???????
                    console.log(stack_mark[k]);
                }
                console.log(stack_mark.length);
                console.log(stack_num.length);
                stack_num.length--;
                console.log(stack_num.length);
                len_num = stack_num.length;
                console.log(len_num);
                
                for(let i = 0,j = 1;i<=len_mark-1;i++,j++){
                    if(stack_mark[i] == '+'){
                        var num1;
                        num1 = Number(stack_num[0]) + Number(stack_num[j]);
                        //stack_num.length = stack_num.length - 1;
                        stack_num[0] = num1;
                        //stack_mark.length = stack_mark.length - 1;
                    }
                    else if(stack_mark[i] == '-'){
                        var num2;
                        num2 = Number(stack_num[0]) - Number(stack_num[j]);
                        //stack_num.length = stack_num.length - 1;
                        stack_num[0] = num2;
                        //stack_mark.length = stack_mark.length - 1;
                    }
                   // console.log(len_num);
                }
                
                console.log(stack_num[0]);
                result = stack_num[0];
                out_box.innerHTML = result;//写在另一个函数中为啥不对?????
            }
            
        </script>

下面是我对每一个函数的大概解释:

  • function submit()
    我们可以看到每一个ininbox都会onclick一个submit()用于将标签之中获取内容来加入我们的strbefore的字符串;这样我们就就可以通过submit来获取我们的表达式了。

  • function get_empty()
    get_empty()函数会在点击c(清空按钮)的时候将我们的所有元素恢复到开始的状态,来进行重新的运算。

  • show()
    在show()中我们实现了对表达式的计算
    大概的思路是:


去构建了两个栈,一个是操作数栈、一个是数字栈;


然后我们去从左到右去扫描我们的字符串当遇到数字的时候,就将数字压入操作数栈,遇到 + 或者 - 的时候压入操作数栈;


因为我们要按照正确的计算方法,所以当遇到 * 和 / 的时候,我们需要取符号的上一个值和下一个值去进行计算之后再压入操作数栈中;


最后我们可以根据我们的这两个栈来完成操作数的加减法。

这里我们会遇到一个问题
当我们遇到一个不是各位数字的时候并不能在字符串中去将它正确的识别,所以我们需要将它转成一个正确的数字。

需要用到的函数:parseFloat(num) 可以将字符串转变为数字。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐