原生JavaScript实现轻量级计算器

深碍√TFBOYSˉ_ 2023-08-17 17:45 169阅读 0赞

  想尝试做一个网页版计算器后,参考了很多博客大神的代码,综合归纳、总结修改,整理如下文。

  附: Demo 源码

一、HTML+CSS

  具体结构样式如下图,基本参照手机计算器界面。按钮功能可以查看demo,都可以实现。

  1123168-20170411173645829-1266169246.png

  这部分布局不是重点,只附上代码以便理解JS行为。

  HTML/结构:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>JS实现轻量级计算器</title>
  6. <link href="css/style.css" type="text/css" rel="stylesheet" />
  7. <script src="js/script.js" type="text/javascript" rel="stylesheet"></script>
  8. </head>
  9. <body>
  10. <div id="box">
  11. <div id="top">
  12. <p>Lightweight Calculator by PYJ</p>
  13. <input id="screen0" type="text" style="margin-top: 100px;" disabled/>
  14. <input id="screen1" type="text" style="margin-top: 190px;" disabled/>
  15. </div>
  16. <div id="main">
  17. <span class="div1" style="font-size: 26px">(</span>
  18. <span class="div1" style="font-size: 26px">)</span>
  19. <span class="div1" style="font-size: 26px">DEL</span>
  20. <span class="div1">/</span>
  21. <span class="div2">7</span>
  22. <span class="div2">8</span>
  23. <span class="div2">9</span>
  24. <span class="div1">*</span>
  25. <span class="div2">4</span>
  26. <span class="div2">5</span>
  27. <span class="div2">6</span>
  28. <span class="div1">-</span>
  29. <span class="div2">1</span>
  30. <span class="div2">2</span>
  31. <span class="div2">3</span>
  32. <span class="div1">+</span>
  33. <span class="div2">0</span>
  34. <span class="div2">.</span>
  35. <span class="div1">C</span>
  36. <span class="div3" style="width: 94px;background: orangered;">=</span>
  37. </div>
  38. </div>
  39. </body>
  40. </html>

  CSS/表现:

  1. *{
  2. margin: 0;
  3. padding: 0;
  4. font-family: "Consolas", "Menlo", "Courier", monospace;
  5. }
  6. span{display: block;}
  7. body{background: #f0f2f1;}
  8. #box{
  9. width: 380px;
  10. height: 675px;
  11. margin-top: 8px;
  12. margin-left: auto;
  13. margin-right: auto;
  14. box-shadow:0 0 10px #888;
  15. }
  16. #top{
  17. width: inherit;
  18. height: 285px;
  19. background: #333333;
  20. position: relative;
  21. }
  22. #top p{
  23. color: #e7e7e7;
  24. font-size: 16px;
  25. padding-top: 5px;
  26. padding-right: 10px;
  27. text-align: right;
  28. }
  29. #top input{
  30. width: 368px;
  31. height: 70px;
  32. position: absolute;
  33. color: #e8e8e8;
  34. background: none;
  35. border: none;
  36. font-size: 35px;
  37. text-align: right;
  38. line-height: 70px;
  39. cursor: text;
  40. padding-right: 10px;
  41. }
  42. #main{
  43. width: inherit;
  44. height: 390px;
  45. background: #f0f2f1;
  46. }
  47. #main span{
  48. width: 94px;
  49. height: 77px;
  50. border-right: 1px solid #dff0d8;
  51. border-top: 1px solid #dff0d8;
  52. float: left;
  53. font-size: 32px;
  54. text-align: center;
  55. line-height: 80px;
  56. cursor: pointer;
  57. }
  58. .div1{color: orangered;}
  59. .div2{color: #000;}
  60. .div3{border-right: none;color: #fff;}
  61. #main span:hover{background: #e1e1e1;}
  62. #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 };

  1. 上面代码最后一行调用了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 }

      分别对清零、回删、“=”和其他字符情况做出判断,给予不同的处理结果。

  1. 按了“=”,就表示要对前面的字符串进行计算了:

  但在计算前,需要了解一下JS数字精度丢失的问题。计算机的二进制的实现和位数限制会使部分数无法有限表示,有穷的数在计算机的二进制里却是无穷的,因存储位数的限制而发生的“舍去”,就导致了精度的丢失。具体内容不再展开,可以去查看相关文档。

  为了解决浮点数的精度丢失问题,在这里为Math对象定义了一个方法:

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

  

  计算器最核心的算法就是表达式的运算。

  本文的思想是,将表达式按符号拆分并运用递归:

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

  需要注意:首先对括号内内容进行运算;“-” 号和除号要从表达式尾部开始提取,否则计算有误;“-” 号有负号和减号之分,解决办法是,在 “-” 号前有乘号和除号时,要按乘号或除号拆分;Math.formatFloat() 方法的运用。


使用效果图如下,存在bug或者文中有错误的话希望指出 [抱拳]

  1123168-20170411190118469-2096546191.png

转载于:https://www.cnblogs.com/Livia-Peng/p/calculate.html

发表评论

表情:
评论列表 (有 0 条评论,169人围观)

还没有评论,来说两句吧...

相关阅读