1. 程式人生 > >jquery實現簡易的計算器

jquery實現簡易的計算器

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <style type="text/css">

        body {
            padding: 20px;
            font-family: Arial;
        }

        .calc-wrap {
            width: 300px;
            border
: 1px solid #ddd; border-radius: 3px; } .calc-operation { width: 100%; border-collapse: collapse; } .calc-in-out { width: 100%; padding: 10px 20px; text-align: right; box-sizing: border-box
; background-color: rgba(250, 250, 250, .9); } .calc-in-out p { overflow: hidden; margin: 5px; width: 100%; } .calc-history { margin-left: -20px; font-size: 18px; color: #bbb; border-bottom
: 1px dotted #ddf; min-height: 23px; } .calc-in, .calc-out { font-size: 20px; color: #888; line-height: 39px; min-height: 39px; } .calc-in { color: #888; } .calc-out { color: #ccc; } .calc-in.active, .calc-out.active { font-size: 34px; color: #666; } .calc-operation td { padding: 10px; width: 25%; text-align: center; border: 1px solid #ddd; font-size: 26px; color: #888; cursor: pointer; } .calc-operation td:active { background-color: #ddd; } .calc-operation .cls { color: #ee8956; } </style> <script src="../jquery/jquery-3.3.1.min.js"></script> <script type="text/javascript"> $(function() { function Calculator($dom) { this.$dom = $($dom); // 歷史運算 this.$history = this.$dom.find('.calc-history'); // 輸入區 this.$in = this.$dom.find('.calc-in'); // 輸出區 this.$out = this.$dom.find('.calc-out'); this.$operation = this.$dom.find('.calc-operation'); // 運算子對映 this.op = { 'plus': '+', 'minus': '-', 'mul': '*', 'div': '/' }; this.opArr = ['+', '-', '*', '/']; // 中綴表示式 this.infix = []; // 字尾表示式 this.suffix = []; // 字尾表示式運算結果集 this.result = []; // 儲存最近的值 this.lastVal = 0; // 當前已經計算等於完成 this.calcDone = false; // 當前正在進行小數點點(.)相關值的修正 this.curDot = false; this.init(); } Calculator.prototype = { constructor: Calculator, // 初始化 init: function() { this.bindEvent(); }, // 繫結事件 bindEvent: function() { var that = this; that.$operation.on('click', function(e) { e = e || window.event; var elem = e.target || e.srcElement, val, action; if (elem.tagName === 'TD') { val = elem.getAttribute('data-val') || elem.getAttribute('data-ac'); // 數字:0-9 if (!isNaN(parseInt(val, 10))) { // 構建中綴表示式並顯示 var infixRe = that.buildInfix(parseInt(val, 10), 'add'); that.$in.text(infixRe.join('')).addClass('active'); that.calculate(); return; } action = val; // 操作:清除、刪除、計算等於 if (['cls', 'del', 'eq'].indexOf(action) !== -1) { if (!that.infix.length) { return; } // 清空資料 if (action === 'cls' || (action === 'del' && that.calcDone)) { that.$in.text(''); that.$out.text(''); that.resetData(); } // 清除 else if (action === 'del') { // 重新構建中綴表示式 var infixRe = that.buildInfix(that.op[action], 'del'); that.$in.text(infixRe.join('')).addClass('active'); that.calculate(); } // 等於 else if (action === 'eq') { that.calculate('eq'); } } // 預運算:百分比、小數點、平方 else if (['per', 'dot', 'sq'].indexOf(action) !== -1) { if (!that.infix.length || that.isOp(that.lastVal)) { return; } if (action === 'per') { that.lastVal /= 100; } else if (action === 'sq') { that.lastVal *= that.lastVal; } else if (action === 'dot') { // that.curDot = true; } // 重新構建中綴表示式 var infixRe = that.buildInfix(that.lastVal, 'change'); that.$in.text(infixRe.join('')).addClass('active'); that.calculate(); } // 運算子:+ - * / else if (that.isOp(that.op[action])) { if (!that.infix.length && (that.op[action] === '*' || that.op[action] === '/')) { return; } var infixRe = that.buildInfix(that.op[action], 'add'); that.$in.text(infixRe.join('')).addClass('active'); } } }); }, resetData: function() { this.infix = []; this.suffix = []; this.result = []; this.lastVal = 0; this.curDot = false; }, // 構建中綴表示式 buildInfix: function(val, type) { // 直接的點選等於運算之後, if (this.calcDone) { this.calcDone = false; // 再點選數字,則進行新的運算 if (!this.isOp(val)) { this.resetData(); } // 再點選運算子,則使用當前的結果值繼續進行運算 else { var re = this.result[0]; this.resetData(); this.infix.push(re); } } var newVal; // 刪除操作 if (type === 'del') { newVal = this.infix.pop(); // 刪除末尾一位數 newVal = Math.floor(newVal / 10); if (newVal) { this.infix.push(newVal); } this.lastVal = this.infix[this.infix.length - 1]; return this.infix; } // 新增操作,首先得判斷運算子是否重複 else if (type === 'add') { // 兩個連續的運算子 if (this.isOp(val) && this.isOp(this.lastVal)) { return this.infix; } // 兩個連續的數字 else if (!this.isOp(val) && !this.isOp(this.lastVal)) { newVal = this.lastVal * 10 + val; this.infix.pop(); this.infix.push(this.lastVal = newVal); return this.infix; } // 首個數字正負數 if (!this.isOp(val) && this.infix.length === 1 && (this.lastVal === '+' || this.lastVal === '-')) { newVal = this.lastVal === '+' ? val : 0 - val; this.infix.pop(); this.infix.push(this.lastVal = newVal); return this.infix; } this.infix.push(this.lastVal = val); return this.infix; } // 更改操作,比如%的預運算 else if (type === 'change') { this.infix.pop(); this.infix.push(this.lastVal = val); return this.infix; } }, // 判斷是否為運算子 isOp: function(op) { return op && this.opArr.indexOf(op) !== -1; }, // 判斷運算子優先順序 priorHigher: function(a, b) { return (a === '+' || a === '-') && (b === '*' || b === '/'); }, // 進行運算子的運算 opCalc: function(b, op, a) { return op === '+' ? a + b : op === '-' ? a - b : op === '*' ? a * b : op === '/' ? a / b : 0; }, // 即時得進行運算 calculate: function(type) { this.infix2Suffix(); var suffixRe = this.calcSuffix(); if (suffixRe) { this.$out.text('=' + suffixRe) .attr('title', suffixRe) .removeClass('active'); // 如果是直接顯示地進行等於運算 if (type === 'eq') { this.$in.removeClass('active'); this.$out.addClass('active'); // 設定標記:當前已經顯示地進行計算 this.calcDone = true; this.lastVal = suffixRe; // 設定歷史記錄 var history = this.infix.join('') + ' = ' + suffixRe; this.$history.text(history).attr('title', history); } } }, // 中綴表示式轉字尾 infix2Suffix: function() { var temp = []; this.suffix = []; for (var i = 0; i < this.infix.length; i++) { // 數值,直接壓入 if (!this.isOp(this.infix[i])) { this.suffix.push(this.infix[i]); } else { if (!temp.length) { temp.push(this.infix[i]); } else { var opTop = temp[temp.length - 1]; // 迴圈判斷運算子優先順序,將運算子較高的壓入字尾表示式 if (!this.priorHigher(opTop, this.infix[i])) { while (temp.length && !this.priorHigher(opTop, this.infix[i])) { this.suffix.push(temp.pop()); opTop = temp[temp.length - 1]; } } // 將當前運算子也壓入字尾表示式 temp.push(this.infix[i]); } } } // 將剩餘運算子號壓入 while (temp.length) { this.suffix.push(temp.pop()); } }, // 字尾表示式計算 calcSuffix: function() { this.result = []; for (var i = 0; i < this.suffix.length; i++) { // 數值,直接壓入結果集 if (!this.isOp(this.suffix[i])) { this.result.push(this.suffix[i]); } // 運算子,從結果集中取出兩項進行運算,並將運算結果置入結果集合 else { this.result.push(this.opCalc(this.result.pop(), this.suffix[i], this.result.pop())); } } // 此時結果集中只有一個值,即為結果 return this.result[0]; } }; new Calculator('.calc-wrap'); }); </script> </head> <body> <!-- 計算器 --> <div class="calc-wrap"> <div class="calc-in-out"> <!-- 上一條運算記錄 --> <p class="calc-history" title=""></p> <!-- 輸入的資料 --> <p class="calc-in"></p> <!-- 輸出的運算結果 --> <p class="calc-out active"></p> </div> <table class="calc-operation"> <thead></thead> <tbody> <tr> <td data-ac="cls" class="cls">C</td> <td data-ac="del">&larr;</td> <td data-ac="sq">x<sup>2</sup></td> <td data-ac="mul">&times;</td> </tr> <tr> <td data-val="7">7</td> <td data-val="8">8</td> <td data-val="9">9</td> <td data-ac="div">&divide;</td> </tr> <tr> <td data-val="4">4</td> <td data-val="5">5</td> <td data-val="6">6</td> <td data-ac="plus">+</td> </tr> <tr> <td data-val="1">1</td> <td data-val="2">2</td> <td data-val="3">3</td> <td data-ac="minus">-</td> </tr> <td data-ac="per">%</td> <td data-val="0">0</td> <td data-ac="dot">.</td> <td data-ac="eq" class="eq">=</td> </tbody> </table> </div> </body> </html>