vue+vuex实现一个计算器效果代码
代码语言:html
所属分类:其他
代码描述:vue+vuex实现一个计算器效果代码
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/vue@2.6.1.js"></script> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/vuex.min.js"></script> <link type="text/css" rel="stylesheet" href="//repo.bfw.wiki/bfwrepo/css/ionicons.css"> <style> @import url("https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,300,400italic,600,700,900,200"); html { box-sizing:border-box; color:#222; font-size:1rem; font-family:Source Sans Pro; line-height:1.5; text-rendering:optimizeLegibility } *,*:before,*:after { box-sizing:inherit } body { background-size:cover; background-repeat:no-repeat; background-color:#B6B2AB; background-image:linear-gradient(135deg,#B6B2AB 0,#B3AFA7 25%,#B8B5AF 25%,#78736B 50%,#6F6862 50%,#58504B 75%,#5F574E 75%,#625A51 100%); min-height:100vh } .App { opacity:0; transition:opacity .3s } .Calculator { box-shadow:12px 18px 45px 0 rgba(0,0,0,0.25); cursor:default; margin:0 auto; transform:translate(-50%,-50%); -webkit-user-select:none; -moz-user-select:none; -ms-user-select:none; user-select:none; position:absolute; top:50%; left:50%; width:260px } .Calculator-header { background:white; overflow:hidden; padding:20px 20px; position:relative; text-align:right } .Calculator-expressions { color:rgba(158,158,158,0.76); display:block; float:right; font-size:15px; line-height:22px; min-height:22px; position:relative; white-space:nowrap; width:100%; word-wrap:normal } .Calculator-expressionsList { display:block; float:right } .Calculator__expressionsOverflow { color:#333; box-shadow:5px 0 20px 4px rgba(0,0,0,0.3); font-weight:700; opacity:0; padding-right:0; text-align:center; transition:opacity .5s; transform:translate(0,-50%); position:absolute; top:50%; left:-24px; height:17px; width:2px } .Calculator__expressionsOverflow:before { content:"" } .Calculator__expressionsOverflow.is-showing { opacity:1 } .Calculator-operands { color:#151515; font-size:60px; font-weight:200; line-height:1.1; clear:both } .Calculator-currentOperand { display:block; overflow:visible; min-height:60px; line-height:60px; float:right; transition-duration:.2s; transition-property:font-size } .Calculator-currentOperand.has-error { color:#ef5334 } .Calculator-body { background:white } .Calculator-buttonsContainer { display:flex; flex-wrap:wrap; overflow:visible; position:relative } .Calculator-buttonsContainer:before { background-color:rgba(90,95,114,0.76); background-image:linear-gradient(to bottom,rgba(90,95,114,0.76),rgba(29,32,37,0.8)); box-shadow:17px 27px 72px 1px rgba(0,0,0,0.3); filter:drop-shadow(0px 0 7px rgba(0,0,0,0.2)); content:""; position:absolute; top:0; right:-18px; bottom:0; left:-18px } .Calculator-button { color:rgba(255,255,255,0.8); cursor:pointer; font-size:24px; font-weight:300; flex:25%; line-height:70px; text-align:center; position:relative; z-index:1 } .Calculator-button { cursor:pointer; transition:box-shadow .2s,background-color .15s; text-shadow:1px 1px 2px rgba(0,0,0,0.15) } .Calculator-button:hover { background:rgba(0,0,0,0.08) } .Calculator-button:active,.Calculator-button.is-active { box-shadow:inset 0 3px 15px 0 rgba(0,0,0,0.3) } .Calculator-button.has-children:hover,.Calculator-button.has-children:active { background:initial; box-shadow:none; cursor:default } .Calculator-button>span { display:block } .Calculator-button--negation,.Calculator-button--modulo { font-size:18px } .Calculator-button--square { font-size:16px } .Calculator-button--division { font-size:20px } .Calculator-button--multiplication { font-size:30px } .Calculator-button--addition { font-size:26px } .Calculator-button--subtraction { font-size:25px } .Calculator-button--paren { display:flex; font-size:18px } .Calculator-button--paren:hover,.Calculator-button--paren:active { background:initial!important; box-shadow:none!important; cursor:default!important } .Calculator-button--paren>span { flex:50% } .Calculator-button--paren>span { cursor:pointer; transition:box-shadow .2s,background-color .15s; text-shadow:1px 1px 2px rgba(0,0,0,0.15) } .Calculator-button--paren>span:hover { background:rgba(0,0,0,0.08) } .Calculator-button--paren>span:active,.Calculator-button--paren>span.is-active { box-shadow:inset 0 3px 15px 0 rgba(0,0,0,0.3) } .Calculator-button--paren>span.has-children:hover,.Calculator-button--paren>span.has-children:active { background:initial; box-shadow:none; cursor:default } .Calculator-equals { background-color:#FF8D4B; background-image:linear-gradient(to right,#FF8D4B,#FF542E); cursor:pointer; padding:26px 0; position:relative; z-index:-1 } .Calculator-equalsLine { background:white; display:block; margin:0 auto 6px; box-shadow:0 0 2px rgba(0,0,0,0.4); height:1px; width:20px } .Calculator-equalsLine:last-child { margin-bottom:0 } </style> </head> <body> <!-- partial:index.partial.html --><template data-template="calculatorbutton"><div class="Calculator-button" v-bind:class="className"><span v-bind:class="['btest', button.icon ? button.icon : '']" v-if="button.children == null" v-text="button.text" @click.stop="emitAction($event, button)"></span><span v-for="childButton in button.children" v-bind:class="[childButton.className || ' btest ', 'btest']" v-text="childButton.text" @click.stop="emitAction($event, childButton)"></span></div></template> <div class="App js-app" v-bind:style="{ opacity: appLoaded ? 1 : 0 }"> <div class="Calculator"> <header class="Calculator-header"> <div class="Calculator-expressions"><span class="Calculator-expressionsOverflow"></span><span class="Calculator-expressionsList">{{expressionList}}</span></div> <div class="Calculator-operands"><span class="Calculator-currentOperand" v-bind:class="{ 'has-error': error }" v-bind:style="{ 'font-size': font.size, 'font-weight': font.weight }">{{operand}}</span></div> </header> <div class="Calculator-body"> <div class="Calculator-buttonsContainer"> <div v-for="button in buttons" is="calculatorbutton" v-bind:button="button">{{button.children}}</div> </div> </div> <div class="Calculator-equals" @click.stop="$store.dispatch('showTotal', { explicit: true })"> <div class="Calculator-equalsLine"></div> <div class="Calculator-equalsLine"></div> </div> </div> </div> <!-- partial --> <script > function main() { 'use strict'; const $ = document.querySelector.bind(document); const $app = $('.js-app'); const templates = { calculatorButton: $(`[data-template="calculatorbutton"]`).innerHTML }; const ACTION_CLEAR = 'clear'; const ACTION_CLEAR_ENTRY = 'clearEntry'; const ACTION_NEGATE = 'negate'; const ACTION_UPDATE_OPERATOR = 'updateOperator'; const ACTION_APPEND_OPERAND = 'appendOperand'; const ACTION_ADD_PAREN = 'addParen'; const ACTION_BACKSPACE = 'backspace'; const ACTION_SHOW_TOTAL = 'showTotal'; const buttons = [ { text: 'C', className: 'clear', action: ACTION_CLEAR }, { text: '+/-', className: 'negation', action: ACTION_NEGATE }, { text: '%', className: 'modulo', action: ACTION_UPDATE_OPERATOR, payload: { operator: '%' } }, { text: '√', className: 'square', action: ACTION_UPDATE_OPERATOR, payload: { operator: 'yroot' } }, { text: '7', action: ACTION_APPEND_OPERAND, payload: { value: '7' } }, { text: '8', action: ACTION_APPEND_OPERAND, payload: { value: '8' } }, { text: '9', action: ACTION_APPEND_OPERAND, payload: { value: '9' } }, { text: '/', className: 'division', action: ACTION_UPDATE_OPERATOR, payload: { operator: '/' } }, { text: '4', action: ACTION_APPEND_OPERAND, payload: { value: '4' } }, { text: '5', action: ACTION_APPEND_OPERAND, payload: { value: '5' } }, { text: '6', action: ACTION_APPEND_OPERAND, payload: { value: '6' } }, { text: '', className: 'multiplication', icon: 'ion-ios-close-empty', action: ACTION_UPDATE_OPERATOR, payload: { operator: '*' } }, { text: '1', action: ACTION_APPEND_OPERAND, payload: { value: '1' } }, { text: '2', action: ACTION_APPEND_OPERAND, payload: { value: '2' } }, { text: '3', action: ACTION_APPEND_OPERAND, payload: { value: '3' } }, { text: '', className: 'subtraction', icon: 'ion-ios-minus-empty', action: ACTION_UPDATE_OPERATOR, payload: { operator: '-' } }, { text: '0', action: ACTION_APPEND_OPERAND, payload: { value: '0' } }, { className: 'paren', children: [ { text: '(', className: 'open-paren', action: ACTION_ADD_PAREN, payload: { operator: '(' } }, { text: ')', className: 'close-paren', action: ACTION_ADD_PAREN, payload: { operator: ')' } }] }, { text: '.', action: ACTION_APPEND_OPERAND, payload: { value: '.' } }, { text: '', className: 'addition', icon: 'ion-ios-plus-empty', action: ACTION_UPDATE_OPERATOR, payload: { operator: '+' } }]; // Mode show total causes the total to be displayed in the current operand display const MODE_SHOW_TOTAL = 1 << 1; // Mode insert operand causes the current operand to be overwritten. After the first character has been written, the mode should go to mode append operand const MODE_INSERT_OPERAND = 1 << 2; // Mode append operand causes any operand parts to be appended to the current operand const MODE_APPEND_OPERAND = 1 << 3; // The maximum number of digits the current operand may be const MAX_NUMBER_LENGTH = Number.MAX_SAFE_INTEGER.toString().length; const initialState = { activeButtons: [], buttons, expressions: ['5', '+', '7', '-', '45', '+', '3', '+', '177', '-'], currentOperand: '147', currentOperator: '-', mode: MODE_SHOW_TOTAL | MODE_INSERT_OPERAND, openParenStack: 0, error: null, total: 147 }; const mutations = { CLEAR(state) { state.expressions = []; state.currentOperand = '0'; state.currentOperator = ''; state.openParenStack = 0; state.mode = MODE_SHOW_TOTAL | MODE_INSERT_OPERAND; state.error = null; state.total = 0; }, BACKSPACE(state) { let operand = state.currentOperand.slice(0, -1); if (operand.length === 0) { operand = '0'; } state.currentOperand = operand; }, CLEAR_ENTRY(state) { state.currentOperand = '0'; }, NEGATE(state) { // Only add negative sign if not zero if (state.currentOperand !== 0) { state.currentOperand = (-state.currentOperand).toString(); } }, UPDATE_OPERATOR(state, { operator }) { const length = state.expressions.length; const last = state.expressions[length - 1] || ''; const { mode, currentOperand } = state; if (mode & MODE_INSERT_OPERAND) { console.log('MODE_INSERT_OPERAND'); if (length === 0) { state.expressions.push(currentOperand, operator); } else if (isOperator(last)) { // console.log('isoplast'); // APPEND_OP LOG state.expressions.pop(); state.expressions.push(operator); } else if (last === ')') { // console.log('nope'); // APPEND_OP LOG state.expressions.push(operator); } else if (last === '(') { state.expressions.push(currentOperand, operator); } else { // console.log('else'); // APPEND_OP LOG } } else if (mode & MODE_APPEND_OPERAND) { console.log('MODE_APPEND_OPERAND'); if (length === 0) { console.log('length 0'); // APPEND_OP LOG state.expressions.push(currentOperand, operator); } else if (isOperator(last)) { // console.log('isOperator(last)'); // APPEND_OP LOG state.expressions.push(currentOperand, operator); } else if (last === ')') { // console.log('last === )'); // APPEND_OP LOG state.expressions.push(operator); } else if (last === '(') { // console.log('last === ('); // APPEND_OP LOG state.expressions.push(currentOperand, operator); } else { // console.log('else'); // state.expressions.push(operator, currentOperand); } } state.currentOperator = operator; state.mode = MODE_INSERT_OPERAND | MODE_SHOW_TOTAL; console.log('UPDATE_OPERATOR:', state.expressions); }, ADD_PAREN(state, { operator }) { const last = state.expressions[state.expressions.length - 1] || ''; const { currentOperand, openParenStack } = state; // console.log('ADD_PAREN:', {last, operator}); if (operator === ')' && openParenStack === 0) { // No need to add closing paren if there is no open paren return; } else if (operator === '(' && last === ')') { // FIXME: Look at real calculator for semantics return; } if (last === '(' && operator === ')') { // Handle immediate closed parens state.expressions.push(currentOperand, operator); } else if (isOperator(last) && operator === ')') { // Automatically append current operand when expressions // is "(5 *" so result is "(5 * 5)" state.expressions.push(currentOperand, operator); } else if ((isOperator(last) || length === 0) && operator === '(') { // Handle "5 *" where the result is "5 * (" and "(" is the beginning // of a new group expression state.expressions.push(operator); } if (operator === '(') { state.openParenStack++; } else if (operator === ')') { state.openParenStack--; } console.log('ADD_PAREN'); }, APPEND_OPERAND(state, { value, operator }) { const currentOperand = state.currentOperand; let newOperand = currentOperand; let newMode; // Don't append 0 to 0 if (value === '0' && currentOperand[0] === '0') { return; } else if (value === '.' && currentOperand.includes('.')) { // Avoid appending multiple decimals return; } // Switch modes from showing the total to the current operand if (state.mode & MODE_SHOW_TOTAL) { newMode = MODE_INSERT_OPERAND; } if (state.mode & MODE_INSERT_OPERAND) { // console.log('INSERT'); newOperand = value.toString(); state.mode = MODE_APPEND_OPERAND; } else { // console.log('APPEND'); newOperand += value.toString(); } // TODO: Update font size, actually should do that in the vm state.currentOperand = newOperand.substring(0, MAX_NUMBER_LENGTH); }, SHOW_TOTAL(state, { $commit, explicit } = {}) { const last = state.expressions[state.expressions.length - 1] || ''; const expressions = state.expressions.slice(0); const currentOperand = state.currentOperand; const mode = state.mode; const currentTotal = state.total; const openParenStack = state.openParenStack; const isFirstNumber = typeof Number(expressions[0]) === 'number'; const isSecondOperator = isOperator(expressions[1] || ''); const length = expressions.length; let times = openParenStack; let total; if (expressions.length === 0) { return; } else if (explicit && isFirstNumber && isSecondOperator && length === 2) { // Handle case where expressions is 5 * // console.log('explicit && isFirstNumber && isSecondOperator'); expressions.push(currentOperand); } else if (explicit && isOperator(last)) { // Handle case where expressions is ['5', '*', '4', '+'] and // the total is being explicitly being requested // console.log('explicit && isOperator(last)', isOperator(last), last); if (mode & MODE_INSERT_OPERAND) { expressions.push(currentTotal); } else if (mode & MODE_APPEND_OPERAND) { expressions.push(currentOperand); } } else if (isOperator(last)) { // Handle case where expressions is ['5', '*', '4', '+'] // console.log('isOperator(last)'); expressions.pop(); } if (explicit) { // Automatically close parens when explicitly requesting // the total let times = openParenStack; while (times-- > 0) { expressions.push(')'); } } else if (!explicit && openParenStack === 1) { // Auto close if there is only one missing paren expressions.push(')'); } try { total = MathParser.eval(expressions.join(' ')); if (explicit) { $commit('CLEAR'); } state.total = total; } catch (err) { if (explicit) { $commit('CLEAR'); state.error = err; console..........完整代码请登录后点击上方下载按钮下载查看
网友评论0