JS 实现计算器详解及实例代码(一)
程序员文章站
2023-11-18 16:49:46
javascript 实现计算器:
系列文章:
js 实现计算器详解及实例代码(一)
javascript 实现计算器时间功能详解及实例(二)
小型javascri...
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'存在;
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!