JS实现HTML在线计算器
作者:强哥   类别:Web前端    日期:2018-10-29 16:14:48    阅读:3089 次   消耗积分:0 分

项目介绍


在前面的章节中,我们已经清楚地知道如何通过Table或DIV对一个HTML在线计算器进行布局。所以本项目演练的核心目的,主要是利用JavaScript编程的方式,来实现该在线计算器的功能,实现效果如图11-2所示。


20181029_160715_449.png 

11-2 在线计算器运行效果

 

我们先来分析一下该项目要实现的功能主要包含哪些方面:

(1) 当输入0~9的数字和5个标准运算符(%,÷,*-+)及小数点时,如实反应在结果框中,便于用户核对输入。

(2) “AC”按钮表示清除所有的结果框内容,“<-”回退则只删除最后一个字符。

(3) “=”按钮对结果框中的用户输入的运算表达式进行计算,并展示其运算结果。

(4) “+/-”按钮表示对某个数字进行正负数切换。

(5) 如果用户输入的表达式出现错误,无法计算其结果,则在结果框提示错误信息。

(6) 不能重复地输入运算符,比如5+-++*6,这样的表达式是不允许存在的。




开发思路


首先,本计算器相对于之前的计算器布局做了两处调整:一是添加了回退按钮,即可以用来删除结果框中的一个字符;二是结果框从DIV换成了文本框,因为文本框本身就是用来做输入用的,更加符合通常的要求,也符合用户的使用习惯。同时,这样的设计还可以让用户直接在文本框中输入,提高输入效率,而不是单纯地通过点击按钮来进行。但是同时,这样的输入也必须要注意到,用户输入的正确性,需要对输入部分进行检测。

同样的方式,我们来对上述的7个功能点进行细致的分析,找到对应的解决方案:


1.运算表达式的输入

运算表达式的输入其实核心点就在于将对应按钮的值,如13+等添加在结果框的最后。那么我们可以使用代码如:“document.getElementById(result).value += 3”这样的代码来完成按钮的输入。当然,我们也可以选择让用户自行输入到文本框中。

 

2.清除结果功能

整体清除结果框的内容,只需要将该结果框的内容设置为一个空字符串即可,比如代码可能是document.getElementById(result).value = “””这样的。

对于回退按钮来说,由于删除的是最后一个字符,所以我们可以使用JavaScript的字符串处理函数substring来对字符串进行截取,截取位置是从0到字符串的长度减1的位置,这样就可以将最后一个位置的字符排除掉。

 

3.计算结果功能

我们既然已经将运算表达式输入进去了,甚至有可能是连续的运算,这个时候,如何能够对结果框中的一段普通的文本进行数学运算,变成一个非常棘手的问题。好在,JavaScript为我们提供了一个非常高效而方便的函数:“eval()”。

eval函数是一个特别的函数,可以将一段字符串解析为一段标准的JS代码来执行。我们可以来看看如下的代码实例:


<script>
    
var str1 = "1+2-3+4-5*6/7+8";
    
document.write(str1);
    
document.write("<br/>");
    
document.write(eval(str1));

    
var str2 = "alert('hello')";
    
document.write(str2);
    
document.write("<br/>");
    
document.write(eval(str2));
</
script>

 

根据上述代码实例,我们可以看到,字符串"1+2-3+4-5*6/7+8""alert('hello')"经过eval函数的解析处理后,会变成一个标准的JS表达式并且执行相应的结果运算。这便是这个函数的神奇之处。所以只要我们输入的表达式是正确的,便可以直接被当作一个代码来执行。

 

4.正负号切换功能

对一个数字进行正负号切换,其核心就是在数字前面添加或去除“-”号,基于此,问题的解决方案有两种:一是直接用0来对其数字进行减法运算,二是获取到该数字的第1位的ASCII码,如果是“-”号则将其删除,变为正数,否则,直接在该数字的最前面添加一个负号即可。两种方式都不复杂,大家任选一种方案即可。

 

5.错误提示信息

对于一个数学表达式来说,出现错误的情况将是非常多的,所以我们很难通过ifelse的方式将所有可能出错的情况全部考虑进去。那么在这种情况下呢,我们建议大家使用JavaScript的异常处理机制。通过捕获eval()函数在运算表达式是出现的异常来提示用户出错信息,这样将会更加容易处理,而且不用将精力关注在错误类型的实现上。

 

6.重复运算符验证

虽然所有的异常和错误我们都可以通过异常处理机制轻松的处理,但是对于用户体验来说却不见得是很好的一种方法。比如用户不小心将运算表达式输错了,这个时候虽然我们会有比较友好的提示,但是却需要让用户再输入一遍。所以最好的方式不是提示错误,而是不要给用户提供犯错误的机会,比如前面章节中给大家提到过的,一个文本框只能限制用户输入数字和小数点,不允许输入其他内容。那么在本计算器当中,我们为什么不可以利用程序去帮助用户减少犯错误的机会呢。

比方说,针对这种重复运算符的情况,我们该如何来避免呢?可以有两种方案:一是检测用户输入的最后一个字符是数字还是符号,如果是符号则不允许再输入一个符号。另外一种方案是每当输入了一个符号后,设置某个标志为true,只有输入了数字后,才将该标志设置为false,表示此时可以输入符号。两种方案,任选一红番区可,复杂度差别不大。


代码实现


我们仍然按照上述的功能点分析思路,来一步一步实现这些功能。首先当然是页面的布局,这一点在前面的项目实战中已经有所涉及,所以不再重复讲解。唯一需要注意的是我们将结果框从DIV修改成了Input文本框,所以此处的HTML代码是这样的:


<div>
    <
input type="text" id="result" />
</
div>

 

当然,其对应的CSS属性也做了小幅调整。细节此处不再赘述,需要的读者可查看最后的整体代码部分。接下来我们按照功能点一个一个来看看其实现方式:

 

1.数字按钮的输入,通过在各按钮处响应单击事件传递不同的参数实现,代码如下:


function clickButton(number) {
    
//  解决长度的问题,根据当前的样式设置决定允许输入的字符个数
    var result = document.getElementById('result').value;
    
if (result.length <= 18) {
        
document.getElementById('result').value += number;
    }
    
else{
        alert(
"本计算器只允许输入18位长度.");
    }

}

 

2.清除和删除功能:


// 删除所有内容

function clearResult() {
    
document.getElementById('result').value = "";
}

 

// 删除最后一位
function backSpace() {
    
var result = document.getElementById('result').value;
    
var newResult = result.substring(0, result.length-1);
    
document.getElementById('result').value = newResult;
}

 

3.结果计算及错误提示:


// 计算最终结果
function calcResult() {
    
var result = document.getElementById('result');
    
try {
        
// 如果没有任何表达式
        if (result.value.length >= 3) {
            result.
value = eval(result.value);
        }
    }
    
catch(e) {
        result.
value = "你输入的表达式有误!";
    }
}

 

4.正负号切换:


function switchSymbol() {
    
// 第一种方式:通过字符串操作切换正负号
    var result = document.getElementById('result');
    
var code = result.value.charCodeAt(0);
    
if (code == 45) {  // 判断第一个字符是否是“-”
        // 从第2个位置开始往后取所有的字符串
        result.value = result.value.substring(1);
    }
    
else {
        result.
value = "-" + result.value;
    }

    
// 第二种方式:用0
    // var result = document.getElementById('result').value;
    // document.getElementById('result').value = 0-result;
}

 

5.重复运算符验证,定义一个全局变量,通过修改该全局变量的值来决定是否可以输入运算符号,代码如下:


var isInputSymbol = false;  // 全局变量,false表示可以输入

 

// 解决符号重复输入的问题
function clickSymbol(symbol) {
    
if (document.getElementById('result').value.length > 0) {
        
if (isInputSymbol == false) {
            
document.getElementById('result').value += symbol;
            
isInputSymbol = true;
        }
    }
}

 

此处需要注意一下的是,当我们成功输入了一个数字以后(即在函数clickButton()中),我们必须将该变量的值修改为false,从而告诉脚本此时可以输入符号。clickButton的代码修改如下:


function clickButton(number) {
    
//  解决长度的问题,根据当前的样式设置决定允许输入的字符个数
    var result = document.getElementById('result').value;
    
if (result.length < 18) {
        
document.getElementById('result').value += number;

isInputSymbol = false;
    }
    
else{
        alert(
"本计算器只允许输入18位长度.");
    }

}

 

最后,我们来看看计算器按键的调用,只列举部分代码调用如下:


<body>
    <
div>
        <
div onclick="clearResult()">AC</div>
        <
div onclick="switchSymbol()">+/-</div>
        <
div onclick="clickButton('7')">7</div>
        <
div onclick="clickSymbol('*')">*</div>
        <
div onclick="backSpace()"><-</div>
        <
div onclick="calcResult()">=</div>
    </
div>
</
div>
</
body>


思维拓展


别看一个小小的计算器,其中暗藏不少BUG,非常考验我们对细节的控制。比如上述的代码,初一看其实是没有什么问题了的。但是我们再进行仔细的测试会发现,还是有一些问题需要我们进行更精确的控制。


由于代码限制了用户只能输入18位,所以并没有考虑到实际的情况,而且这18位是表达式的长度,而不是一个数字的长度,所以与我们真实的计算器的运算规律是有所差别的。当然,这样的问题其实解决方案并不难,我们可以设置一个隐藏的元素,如一个DIV或一个文本框,将其隐藏起来,把用户输入的所有内容重新串成一个表达式,当单击“=”号时,直接从该隐藏的文本框中提取表达式从面运算其结果即可。


另外一个方面,我们会发现,虽然我们很好地处理了运算符的连续输入的问题,但是并没有处理小数点的连续输入。而且还有一个更需要注意的问题,即使我们利用类似运算符重复的处理方式很好地处理了连续输入的小数点,让其不能够进行连续输入,但是类似这种形式的数字:“56.34.56.89”其实也是一个不合格的数值,但是小数点并不连续,所以这也是我们需要规避的问题。那么像这种问题,又该如何处理呢?


其实方法也是雷同的,通过设定标志变量来决定是否用户还可以继续输入小数点。比如我们可以设定一个标志变量,假设称为isInputPoint,默认值为false,表示还没有输入小数点,可以允许小数点的存在。这个跟符号的判断一样,但是重点的区别在于,什么时候可以允许再输入小数点呢,不是输入了一个数字以后可以允许再输入,而是只有当输入了一个运算符以后,才允许输入一个小数点。这样就可以实现对小数点的限制,核心代码如下:


// 小数点重复的问题
function clickPoint() {
    
if (isInputPoint == false) {
        
document.getElementById('result').value += ".";
        
isInputSymbol = true;   // 不允许输入运算符
        isInputPoint = true;   // 可以允许输入小数点
    }
}

 

当然,上述代码只是表达其核心思想,要将该代码运行起来,我们还需要定义全局变量,还需要修改clickSymbol()函数等。那么这样我们的计算器功能就实现得很完整了吗?答案是否定的,笔者再给大家举一个例子,比如我们现在可以试着输入一个运算表达式“025-6”,我们可以看看答案是多少?你并没有看错,答案是15,而不是19,很显然这个表达式是有问题的。所以0不能作为一个整数的开头,只能作为一个小数的开头,那么这样的功能点又该如何用代码来进行控制呢?对于这一功能的实现,就留给大家来进行处理了,此处不再详细讲解。


最后,对本项目进行一个简单的总结。一方面我们期望通过该项目的演练让大家充分理解到,开发思路和重要性,其实开发思路本身就是我们的算法。只有把思路想得很明白了,我们再用代码来实现才会更加有自信。另外一方面,我们的代码必须要考虑各种可能的测试场景,设计有针对性的测试用例,而不是用最普通的测试简单试一下,发现没有问题就觉得代码已经可以正常工作了,还是那句话,质量意识才是关键,这跟编程能力无关。作为一个高级程序员,作为一个软件开发或软件测试工程师,都是如此。





为了答谢大家对蜗牛学院的支持,蜗牛学院将会定期对大家免费发放干货,敬请关注蜗牛学院的官方微信。


20181009_153045_341.jpg


   
版权所有,转载本站文章请注明出处:蜗牛笔记, http://www.woniunote.com/article/207
上一篇: JS函数应用与TDD测试驱动开发
下一篇: JS中的正则表达式应用
提示:登录后添加有效评论可享受积分哦!
最新文章
    最多阅读
      特别推荐
      回到顶部