JS 實現計算器詳解及實例代碼(一)
Javascript 實現計算器:
系列文章:
小型JavaScript計算器
自己尋思出的解決方案,比較笨拙的方法,雖然完成了但是還有不少bug,用的方法也不是最有效的,基本功能算是完成了,一些小的細節(jié)地方也考慮到了,但是還有其他的細節(jié)需要處理。
總體設計思路是,先畫草圖 -> 設計UI -> 編寫UI代碼 -> 編寫CSS -> 編寫JS邏輯代碼;
面板(main-board)
面板整體尺寸設計

標題欄(board-title)
- 字體: font: 30px/50px “Comic Sans MS”, “微軟雅黑”;
- 寬高:(100%, 50px);
屏顯區(qū)(board-result)
- 數字顯示區(qū)(result-up):
- 表達式顯示區(qū)(result-down):
按鈕區(qū)(board-keys),使用表格完成,然后給每個td添加onclick事件
完成界面

導入新字體
// main.css
@font-face {
font-family: Lovelo-Black;/×定義font的名字×/
src: url('font/Lovelo Black.otf');/*把下載的字體文件引入進來×/
}
代碼分析
代碼組織結構
計算器對象:Calculator;
計算器屬性:
- bdResult: 計算器面板上的屏顯區(qū)DOM對象;
- operator:操作符數組,包括'+,-,×,÷,=';
- digits:有效數字字符,包括'0-9'和點'.';
- dot, equal, zero:'.', ‘=', ‘0'對應三個字符,點,等號,字符'0';
- digit:屏顯區(qū)上層的顯示的當前輸入的數字;
- expression:屏顯區(qū)下層的顯示的輸入的數字和操作符組成的表達式;
- resSpan:屏顯區(qū)上層的顯示當前數字的span對象;
- resDown:屏顯區(qū)下層的顯示表達式的div對象;
- last:上一次輸入的按鈕內容;
- allDigits:用表達式解析出來的表達式中所有的有效數字;
- ops:用表達式字符串解析出來的表達式中所有的操作符;
- hasEqual:判斷是否按了'='等號的標識符;
- lastRes:上一次計算出來的結果[TODO],尚未用到,待實現可以連續(xù)計算;
計算器方法:
- init:計算器初始化方法;
- addTdClick:給每個td即計算器按鈕添加點擊事件;
- calculatorClickEvent:點擊事件;
- btnClickHanlder:點擊事件處理函數;
- showCurrRes:處理屏顯區(qū)上層和下層將要顯示的內容;
- showText:將通過showCurrRes處理的結果顯示出來;
- addZero:對表達式前面加'0'操作;
- calResult:計算結果;
- clearData:清空數據;
- hasOperator:判斷表達式中是否有操作符;
- isOperator:判斷當前字符是否是操作符;
- delHeadZero:刪除表達式開頭的'0';
輔助方法
- getResSpan:獲取屏顯上層的span對象;
- $tag:根據標簽名去獲取標簽對象;
- $:根據id去獲取DOM對象;
代碼邏輯
使用方法
- 引入Calculator.js文件(在編寫完UI的基礎上)
- 創(chuàng)建對象并初始化:new Calculator().init();
計算器對象
// 計算器對象
function Calculator() {
// 私有屬性
this.bdResult = $("board-result"); // 計算機面板結果顯示區(qū)對象
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(); // 數字顯示區(qū)
this.resDown = $("result-down"); // 表達式顯示區(qū)
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) { // 數字鍵處理
// 如果上一個是操作符,則清空當前數字區(qū)
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); // 計算結果顯示在表達式區(qū)域
return;
} else if (this.isOperator(this.last)) {
// 上一個是操作符,此次的操作符不做記錄
return;
} else {
this.expression += btnText;
}
}
this.showCurrRes(this.digit, this.expression);
this.last = btnText;
};
處理將要顯示的表達式和當前輸入的數字
// 顯示當前結果的觸發(fā)方法
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);
};
將處理結果顯示到屏顯區(qū)
// 將表達式和計算結果顯示到屏顯區(qū)
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;
};
其他函數
// 獲取輸入的數字顯示區(qū)對象
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'存在;
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
- AngularJS ng-blur 指令詳解及簡單實例
- 老生常談onBlur事件與onfocus事件(js)
- jsp+ajax實現的局部刷新較驗驗證碼(onblur事件觸發(fā)較驗)
- javascript委托(Delegate)blur和focus用法實例分析
- Js中的onblur和onfocus事件應用介紹
- AngularJS Controller作用域
- JSP頁面跳轉方法小結
- 詳解js中==與===的區(qū)別
- js時間控件只顯示年月
- java后端把數據轉換為樹,map遞歸生成json樹,返回給前端(后臺轉換)
- 完美解決node.js中使用https請求報CERT_UNTRUSTED的問題
- JS實現iframe自適應高度的方法示例
- Javascript blur與click沖突解決辦法
- jsp頁面顯示數據庫的數據信息表
相關文章
JavaScript對象創(chuàng)建及繼承原理實例解剖
本文將用實例講解一下JavaScript對象創(chuàng)建及繼承原理:JavaScript中的繼承是使用原型鏈的機制,對象創(chuàng)建使用Function構造器,感興趣的朋友可以詳細了解下本文,或許可以幫助到你2013-02-02
javascript與java有什么關系(區(qū)別與相似)
Java和JavaScript的編程語言,名稱聽起來相似,但卻是兩個公司開發(fā)的不同的產品。Java是SUN公司推出的新一代面向對象的程序設計語言,特別適合于Internet應用程序開發(fā);而JavaScript是Netscape公司的產品,可以嵌入Web頁面中的基于對象和事件驅動的解釋性語言。2023-02-02

