Javascript计算器

小型JavaScript计算器

自己寻思出的解决方案,比较笨拙的方法,虽然完成了但是还有不少bug,用的方法也不是最有效的,基本功能算是完成了,一些小的细节地方也考虑到了,但是还有其他的细节需要处理。总体设计思路是,先画草图 -> 设计UI -> 编写UI代码 -> 编写CSS -> 编写JS逻辑代码;

面板(main-board)

  • 面板整体尺寸设计

整体面板尺寸

  • 标题栏(board-title)

    • 字体: font: 30px/50px “Comic Sans MS”, “微软雅黑”;
    • 宽高:(100%, 50px);
  • 屏显区(board-result)

    • 数字显示区(result-up):
    • 表达式显示区(result-down):
  • 按钮区(board-keys),使用表格完成,然后给每个td添加onclick事件

  • 完成界面

界面最终呈现结果

  • 导入新字体

    // main.css
    @font-face { 
    font-family: Lovelo-Black;/×定义font的名字×/ 
    src: url('font/Lovelo Black.otf');/*把下载的字体文件引入进来×/ 
    } 

代码分析

  • 代码组织结构

    • 计算器对象:Calculator;
    • 计算器属性:
      • bdResult: 计算器面板上的屏显区DOM对象;
      • operator:操作符数组,包括’+,-,×,÷,=’;
      • digits:有效数字字符,包括’0-9’和点’.’;
      • dot, equal, zero:’.’, ‘=’, ‘0’对应三个字符,点,等号,字符’0’;
      • digit:屏显区上层的显示的当前输入的数字;
      • expression:屏显区下层的显示的输入的数字和操作符组成的表达式;
      • resSpan:屏显区上层的显示当前数字的span对象;
      • resDown:屏显区下层的显示表达式的div对象;
      • last:上一次输入的按钮内容;
      • allDigits:用表达式解析出来的表达式中所有的有效数字;
      • ops:用表达式字符串解析出来的表达式中所有的操作符;
      • hasEqual:判断是否按了’=’等号的标识符;
      • lastRes:上一次计算出来的结果[TODO],尚未用到,待实现可以连续计算;
    • 计算器方法:

      • init:计算器初始化方法;
      • addTdClick:给每个td即计算器按钮添加点击事件;
      • calculatorClickEvent:点击事件;
      • btnClickHanlder:点击事件处理函数;
      • showCurrRes:处理屏显区上层和下层将要显示的内容;
      • showText:将通过showCurrRes处理的结果显示出来;
      • addZero:对表达式前面加’0’操作;
      • calResult:计算结果;
      • clearData:清空数据;
      • hasOperator:判断表达式中是否有操作符;
      • isOperator:判断当前字符是否是操作符;
      • delHeadZero:删除表达式开头的’0’;
    • 辅助方法

      • getResSpan:获取屏显上层的span对象;
      • $tag:根据标签名去获取标签对象;
      • $:根据id去获取DOM对象;
  • 代码逻辑

    • 使用方法

      • 引入Calculator.js文件(在编写完UI的基础上)
      • 创建对象并初始化:new Calculator().init();
    • 计算器对象

      // 计算器对象
      function Calculator() {
      
          // 私有属性
          this.bdResult   = $("board-result");   // 计算机面板结果显示区对象
          this.operator   = ['+', '-', '×', '÷', '='];
          this.digits     = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.']; // 组成有效数字的数字数组
          this.dot        = '.';
          this.equal      = '=';
          this.zero       = '0';
          this.digit      = "";                   // 当前输入的数字
          this.expression = "";                   // 表达式
          this.resSpan    = getResSpan();     // 数字显示区
          this.resDown    = $("result-down");    // 表达式显示区
          this.last       = "";                   // 上一次按下的按钮内容
          this.allDigits  = [];                   // 从表达式中获取的所有数字组成的数组,将用来和ops中的操作符对应计算出结果                
          this.ops        = [];                   // 所有操作符组成的数组
          this.hasEqual   = false;                // 判断是否按下了'='键
          this.lastRes    = 0;                    // 上一次计算的结果,即上一次按等号后计算出的值
      
      
          // 私有方法
      
      }
    • 添加点击事件(注意this在闭包里的引用问题)

      // 为td添加点击事件
      Calculator.prototype.addTdClick = function () {
      
          var tds         = $tag("td");
          var that        = this;  // 需要注意保存this的引用
          // 为每个td添加点击事件
          for (var i = 0; i < tds.length; i++) {
              tds[i].onclick = function (){
                  // alert(this.innerText);
                  var text = this.innerText;
      
                  that.calculatorClickEvent(text);
              };
          }
      };
      
    • 计算器点击事件处理入口

      // 计算器按钮事件
      Calculator.prototype.calculatorClickEvent = function (btnText) {
      
          // 上一个按键是'='
          if (this.hasEqual) {
              this.hasEqual = false;
              this.clearData();
          }
      
          // 结果显示在board-result里
          if (btnText != "AC" && btnText != "CE") {
              this.btnClickHanlder(btnText);
          } else { // AC或CE清零
              this.clearData();
          }
      };
    • 计算器点击事件处理程序

      // 计算器的按键事件处理
      Calculator.prototype.btnClickHanlder = function (btnText) {
      
          if ((btnText >= '0' && btnText <= '9') || btnText == this.dot) { // 数字键处理
      
              // 如果上一个是操作符,则清空当前数字区
              if (this.isOperator(this.last)) {
                  this.resSpan.innerText = '';
                  this.digit = '';
              } else if ((btnText == this.dot) && (this.last == this.dot)) {
                  // 如果上一个也是点,则对本次的点按钮不做响应
                  return;
              }
      
              this.digit += btnText;
              this.expression += btnText;
          } else if (this.isOperator(btnText)) { // 操作符处理
      
              // 如果当前表达式为'0',按'=',不给响应
              if ((btnText == this.equal) && (this.resDown.innerText == this.zero || this.resDown.innerText == "")) return;
              // 如果上一个是非'='的操作符则不进行处理
              if (!this.isOperator(this.last) && btnText == this.equal) {   // '='处理
      
                  this.showCurrRes(this.zero, this.expression + btnText); // 计算结果显示在表达式区域
                  return; 
              }  else if (this.isOperator(this.last)) {
                  // 上一个是操作符,此次的操作符不做记录
                  return;
              } else {
                  this.expression += btnText;
              }
      
          }
      
          this.showCurrRes(this.digit, this.expression);
      
          this.last = btnText;
      };
    • 处理将要显示的表达式和当前输入的数字

              // 显示当前结果的触发方法
      Calculator.prototype.showCurrRes = function (digit, expression) {
      
          if (!expression) return;
      
          this.showText(digit, expression);
      
          // 1. 没有'=',表示还没有到计算结果的时候,直接退出
          if (expression.indexOf(this.equal) == -1) return;
      
          // 计算出了结果
          this.hasEqual = true;
      
          // 2. 处理只按了数字然后直接按了等号的情况,即:'234='则直接返回234
          var tmpStr = this.delHeadZero(expression.substr(0, expression.length - 1)); // 去掉最后一个'='
          if (!this.hasOperator(tmpStr)) {
              this.showText(tmpStr, expression + tmpStr);
              return;
          } 
      
          // 3. 处理表达式字符串,且计算出结果
          var start   = 0;
          for (var i = 0; i < expression.length; i++) {
      
              var c = expression[i];
              if (this.isOperator(c)) { // 操作符
                  this.ops.push(c);   // 保存操作符
                  var numStr = expression.substr(start, i + 1);  // 数字字符串
                  var number = 0;
      
                  // 浮点数和整型处理
                  if (numStr.indexOf(this.dot)) {
                      number = parseFloat(numStr);
                  } else {
                      number = parseInt(numStr);
                  }
                  this.allDigits.push(number); // 保存数字
                  start = i + 1; // 重设数字起始位置,即操作符的下一个字符开始
              }
          }
      
          // 用allDigits和ops去计算结果
          var res = this.calResult();
      
          // 保存此次计算结果,作为下一次计算用 [TODO]
          this.lastRes = res;
      
          // 将结果显示出来
          this.showText(res + '', expression + res);
      };
    • 将处理结果显示到屏显区

      
      // 将表达式和计算结果显示到屏显区
      Calculator.prototype.showText = function (digitStr, expression) {
      
          // 先删除开头的'0'
          var expStr = this.delHeadZero(expression);
          var digStr = this.delHeadZero(digitStr);
      
          // 然后再根据情况决定是否添加'0'
          var tmp =  expression == this.zero ? expression : this.addZero(expStr);;
          var dig =  digitStr == this.zero ? digitStr : this.addZero(digStr);
      
          this.resSpan.innerText = dig;
      
          // 如果表达式第一个是操作符,则表示之前按的是'0',则给补上'0',因为前面将开头的'0'都删掉了
          if (this.isOperator(tmp[0])) {
              tmp = this.zero + tmp;
          }
      
          this.resDown.innerText = tmp;
      }
    • 计算结果函数

      // 计算结果
      Calculator.prototype.calResult = function () {
          var first   = 0;
          var second  = 0;
          var res     = 0;
          for (var i = 0; i < this.ops.length; i++) {
              first   = this.allDigits[i];
              second  = this.allDigits[i + 1];
              switch (this.ops[i]) {
                  case '+':
                      res = first + second;
                      break;
                  case '-':
                      res = first - second;
                      break;
                  case '×':
                      res = first * second;
                      break;
                  case '÷':
                      res = first / second;
                      break;
                  default:
                      break;
              }
      
              this.allDigits[i + 1] = res;
          }
      
          return res;
      };
      
    • 清空数据

      // 计算完一次,清空所有数据,以备下次计算使用
      Calculator.prototype.clearData = function () {
          this.allDigits  = [];
          this.ops    = [];
          this.expression = this.zero;
          this.digit  = '';
      
          this.resSpan.innerText = this.zero;
          this.resDown.innerText = this.zero;
      };
  • 辅助函数

    • 处理表达式开头的’0’问题(第一个按钮是0键或者第一个是小于1的浮点数,表达式需要补零;)

      // 开头添加'0',防止重复出现或者没有'0'情况
      Calculator.prototype.addZero = function (expression) {
      
          if (!expression) return this.zero;
      
          if (expression[0] == this.dot) { // 浮点数
              return this.zero + expression;
          } else {
              return expression;
          }
      };
    • 开头去零函数

      // 去开头的零
      Calculator.prototype.delHeadZero = function (str) {
      
          // 先把开头的‘0’都删掉
          var tmp = "";
          tmp = str.replace(/^[0]+/gi, "");
          if (tmp[0] == this.dot) {  // 浮点数重新补上'0'
              tmp = this.zero + tmp;
          }
      
          return tmp;
      };
    • 判断字符串里是否含有操作符

      // 判断表达式中是否含有操作符
      Calculator.prototype.hasOperator = function (str) {
      
          if (!str) return;
      
          for (var i = 0; i < this.operator.length; i++) {
              if (str.indexOf(this.operator[i]) >= 0) {
                  return true;
              }
          }
      
          return false;
      };
    • 其他函数

      // 获取输入的数字显示区对象
      function getResSpan() {
          return $("result-up").getElementsByTagName("span")[0];
      }
      
      // 根据标签名获取DOM对象
      function $tag(tagName) {
          return document.getElementsByTagName(tagName);
      }
      
      // 根据ID获取DOM对象
      function $(id) {
          return document.getElementById(id);
      }
  • 问题

    • 文字底部显示:通过设置行高处理;
    • 通过一次性解析表达式需要考虑表达式开头是否需要’0’存在;
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

若叶岂知秋vip

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值