vue+vuex实现一个计算器效果代码

代码语言:html

所属分类:其他

代码描述:vue+vuex实现一个计算器效果代码

代码标签: 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