JavaScript实现一个计算器

FCC-JavaScript写一个计算器

Happy coding.
废话不多说直接上代码。


效果:传送门


HTML代码

html代码并没有什么好讲的;其中比较重要的点就是根据每个buttonname中的值来区别一些特别的操作,比如平方、开根号等等,然后为了更好的用户体验,在每个button用一个a标签包裹,设置title属性,用来提醒该button是什么操作。

<div class="calculator">
    <h1>Zhuo Calculator</h1>
    <div class="prev-result" id="prev-result"></div>
    <div class="result" id="result">0</div>
    <div class="buttons">
      <a title="左括号">
        <button class="button" value="(" name="normal">(</button>
      </a>
      <a title="右括号">
        <button class="button" value=")" name="normal">)</button>
      </a>
      <a title="平方">
        <button class="button" value="sqr" name="special">²</button>
      </a>
      <a title="开根号">
        <button class="button" value="sqrt" name="special">√ ̄</button>
      </a>
      <button class="button" value=" " name="special">&nbsp;</button>
    </div>
    <div class="buttons">
      <a title="非运算">
        <button class="button" value="~" name="normal">~</button>
      </a>
      <a title="或运算">
        <button class="button" value="|" name="normal">|</button>
      </a>
      <a title="与运算">
        <button class="button" value="&" name="normal">&</button>
      </a>
      <a title="左移运算">
        <button class="button" value="<<" name="normal">&lt;&lt;</button>
      </a>
      <a title="右移运算">
        <button class="button" value=">>" name="normal">&gt;&gt;</button>
      </a>
    </div>
    <div class="buttons">
      <a title="返回上一步">
        <button class="button danger" value="AC" name="special"></button>
      </a>
      <a title="全部清除">
        <button class="button" value="CE" name="special">CE</button>
      </a>
      <a title="乘号">
        <button class="button" value="*" name="normal">×</button>
      </a>
      <a title="除号">
        <button class="button" value="/" name="normal">÷</button>
      </a>
      <a title="将输入的十进制转换成十六进制数">
        <button class="button" value="16" name="special">Hex</button>
      </a>
    </div>
    <div class="buttons">
      <button class="button" value="7" name="normal">7</button>
      <button class="button" value="8" name="normal">8</button>
      <button class="button" value="9" name="normal">9</button>
      <a title="取余运算,列如:2%4=2">
        <button class="button" value="%" name="normal">Mod</button>
      </a>
      <a title="将输入的十进制转换成十进制数">
        <button class="button" value="10" name="special">Dec</button>
      </a>
    </div>
    <div class="buttons">
      <button class="button" value="4" name="normal">4</button>
      <button class="button" value="5" name="normal">5</button>
      <button class="button" value="6" name="normal">6</button>
      <a title="加号">
        <button class="button" value="+" name="normal">+</button>
      </a>
      <a title="将输入的十进制转换成八进制数">
        <button class="button" value="8" name="special">Oct</button>
      </a>
    </div>

    <div class="buttons">
      <button class="button" value="1" name="normal">1</button>
      <button class="button" value="2" name="normal">2</button>
      <button class="button" value="3" name="normal">3</button>
      <a title="减号">
        <button class="button" value="-" name="normal">-</button>
      </a>
      <a title="将输入的十进制转换成二进制数">
        <button class="button" value="2" name="special">Bin</button>
      </a>
    </div>
    <div class="buttons">
      <button class="button zero" value="0" name="normal">0</button>
      <button class="button" value="." name="normal">.</button>
      <button class="button" value="=" name="special">=</button>
      <a title="获取上一步的结果">
        <button class="button" value="And" name="special">Ans</button>
      </a>
    </div>
  </div>

CSS代码

CSS给界面增加亮点,添加一些动画,会带来更好的体验。


@charset "UTF-8";
/**
 *
 * @authors Zhuo ([email protected])
 * @date    2018-07-27 15:33:18
 * @version 1.0.1
 */
@import url(https://fonts.googleapis.com/css?family=Oleo+Script);


::selection {
  background: #fff;
  color: #f19953;
}

::-moz-selection {
  background: #fff;
  color: #f19953;
}

::-webkit-selection {
  background: #fff;
  color: #f19953;
}
::-webkit-scrollbar {
    width: 5px;
    height: 5px;
}

::-webkit-scrollbar-track-piece {
    background-color: rgba(0, 0, 0, 0.2);
    -webkit-border-radius: 6px;
}

::-webkit-scrollbar-thumb:vertical {
    height: 5px;
    background-color: rgba(125, 125, 125, 0.7);
    -webkit-border-radius: 6px;
}

::-webkit-scrollbar-thumb:horizontal {
    width: 5px;
    background-color: rgba(125, 125, 125, 0.7);
    -webkit-border-radius: 6px;
}

@keyframes get-result{
  0%{

  }
  100%{
    -webkit-transform-origin: top right;
    -moz-transform-origin: top right;
    -ms-transform-origin: top right;
    -o-transform-origin: top right;
    transform-origin: top right;
    -webkit-transform: scale(0.5) translate(0, -60px);
    -ms-transform: scale(0.5) translate(0, -60px);
    -o-transform: scale(0.5) translate(0, -60px);
    transform: scale(0.5) translate(0, -60px);

  }
}
@keyframes get-prev-result{
  0%{

  }
  100%{
    -webkit-transform-origin: top right;
    -moz-transform-origin: top right;
    -ms-transform-origin: top right;
    -o-transform-origin: top right;
    transform-origin: top right;
    -webkit-transform:  scale(1.4) translate(0, 23px);
    -ms-transform:  scale(1.4) translate(0, 23px);
    -o-transform:  scale(1.4) translate(0, 23px);
    transform:  scale(1.4) translate(0, 23px);
  }
}


@keyframes bomb{
  0%{
    -webkit-transform: scale(1);
    -ms-transform: scale(1);
    -o-transform: scale(1);
    transform: scale(1);
  }
  25%{
    -webkit-transform: scaleX(1.2);
    -ms-transform: scaleX(1.2);
    -o-transform: scaleX(1.2);
    transform: scaleX(1.2);
  }
  50%{
    -webkit-transform: scale(0.8, 1.2);
    -ms-transform: scale(0.8, 1.2);
    -o-transform: scale(0.8, 1.2);
    transform: scale(0.8, 1.2);
  }
  75%{
    -webkit-transform: scaleX(1.2);
    -ms-transform: scaleX(1.2);
    -o-transform: scaleX(1.2);
    transform: scaleX(1.2);
  }
}

html, body {
  background-color: #56351E;
}


h1 {
  font-size: 1.25em;
  font-family: 'Oleo Script', cursive;
  margin: 0 0 10px 0;
  color: #F19953;


  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  -o-user-select: none;
  user-select: none;
}

button {
  height: 50px;
  border: none;
  outline: none;
}

.calculator {
  text-align: center;
  width: 307px;
  height: 535px;
  min-height: 535px;
  border-radius: 10px;
  margin: auto;
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;
  background-color: #010101;
  padding: 5px;
}

.buttons {
  width: 100%;
  text-align: center;
  margin: 5px auto 0;
  font-size: 0;

  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  -o-user-select: none;
  user-select: none;
}

.button{
  width: 18%;
  color: #f19953;
  font-size: 16px;
  margin: 0 3px;
  background: #fff;
  cursor: pointer;

  border-radius: 40% / 35%;
  -webkit-transition: all .2s ease-in-out 0s;
  -o-transition: all .2s ease-in-out 0s;
  transition: all .2s ease-in-out 0s;
}

.button:hover {
  color: #fff;
  background: #f19953;
  animation: bomb .3s 1;
}
.button:focus {
  color: #fff;
  background: #f19953;
  animation: bomb .3s 1;
}


.zero{
  width: 38%;
  text-align: left;
  text-indent: 1em;
  border-radius: 20% / 50%;
}

.danger{
  color: #fff;
  border-color: #d43f3a;
  background-color: #d9534f;
}

.prev-result{
  width: 98%;
  min-height: 26px;
  color: #f1f1f1;
  font-size: 20px;
  text-align: right;
  word-break: break-all;
}

.result {
  width: 98%;
  min-height: 50px;
  max-height: 80px;
  font-size: 30px;
  margin: 10px 0;
  color: #fff;
  text-align: right;
  word-break: break-all;
  overflow-y: auto;

  -webkit-transition: all .3s ease-out .1s;
  -o-transition: all .3s ease-out .1s;
  transition: all .3s ease-out .1s;
  /*animation: get-result .5s 1;*/
}







@media (min-width: 992px) {
  html, body{
    background-color: #56351E;
  }
}
@media (min-width: 1px) and (max-width: 400px) {
  html, body{
    background-color: #010101;
  }
  .calculator{
    width: 95%;
  }
}

JS代码

这里一开始利用了闭包+工厂模式,相当于一个普通的闭包(不理解的可以跳过);


/**
 * 修复一些计算的bug
 *
 * @authors Zhuo ([email protected])
 * @date    2018-07-27 15:33:39
 * @version 1.0.2
 *
 */
(function(global, factory) {
  factory(global);
})(typeof window !== 'undefined' ? window : this,
  function(window, noGlobal) {
    var expression = [], // 用来存储输入的表达式
      RESULT = []; // 保存每次运算后的结果


    var btnNormal = document.getElementsByName('normal'),
      btnSpecial = document.getElementsByName('special'),
      result = document.getElementById('result'),
      prevResult = document.getElementById('prev-result');

    var calculator = function() {
      calculator.fn.init();
    };

    calculator.fn = calculator.prototype = {

      constructor: calculator, // 指定构造函数
      count: 0,

      init: function() {
        var _this = this;
        var val;
        // 给每个按钮添加点击事件
        for (let i = 0; i < btnNormal.length; i++) {
          btnNormal[i].onclick = function() {
            val = this.value;

            _this.push(val);
            _this.showExp();
          };
        }
        // 这里要给每一个特殊的按钮添加相应的功能
        for (let i = 0; i < btnSpecial.length; i++) {
          btnSpecial[i].onclick = function() {
            val = this.value;

            switch (val) {
              case 'AC':
                _this.delete();
                _this.showExp();
                break;
              case 'CE':
                _this.deleteAll();
                _this.showExp();
                break;
              case '=':
                _this.showResult(_this.getResult());
                break;
              case 'And':
                _this.getPervResultDown(_this.getPervResult());
                break;
              case '2':
              case '8':
              case '10':
              case '16':
                _this.showExp(_this.toString(val));
                break;
              case 'sqr':
                _this.showResult(_this.pow(2));
                break;
              case 'sqrt':
                _this.showResult(_this.pow(0.5));
                break;
              case ' ':
                _this.eggshell();
                console.log(_this.count);
            }

          };
        }

      },
      // 计算一个数的次方
      pow: function(n) {
        n = n || 1;
        var result = this.getResult() || 0;
        result = Math.pow(result, n);
        // this.deleteAll();
        // RESULT.push(result);

        return result;
      },
      // 转换进制      
      // 注:这里最好不要用toString的函数名,博猪当时脑袋秀逗了,采用了这个函数名
      toString: function(base) {
        var result = this.getResult() || 0;
        return result.toString(base);
      },

      // 这是一个可以忽视的功能
      eggshell: function() {
        var text = '';
        if (++this.count === 1) {
          text = '别点';
        } else if (this.count === 2) {
          text = '求别点';
        } else if (this.count === 3) {
          text = '我只是一个凑数的,不要再点了';
        } else {
          return;
        }
        this.showPrevResult(text);
      },
      // 将输入的数push到expression数组中
      push: function(exp) {
        expression.push(exp);
      },
      // 将expression数组pop
      pop: function() {
        if (expression.length < 1) {
          return undefined;
        }
        expression.pop();
      },
      // 将上一步输入的数/符号删除
      delete: function() {
        this.pop();
      },
      // 将expression中的所有东西删除
      deleteAll: function() {
        expression = [];
        this.showExp(0);
      },
      // 将上一个结果在RESULT数组中取出,并添加一个从上面跳动到下面的动画
      getPervResultDown: function(val) {
        var _this = this;

        _this.deleteAll();
        _this.push(val);
        prevResult.style.animation = 'get-prev-result .5s 1';

        setTimeout(function() {
          _this.showExp(val);
          _this.showPrevResult();
          prevResult.style.animation = '';
        }, 500);
      },
      // 获取上一个结果的值,并在RESULT中删除
      getPervResult: function() {
        if (RESULT.length < 1) return 0;
        return RESULT.pop();
      },
      // 获取到expression中合法的表达式中的结果
      getResult: function() {
        var result;
        try {
          result = eval(expression.join(''));
        } catch (e) {
          result = '请正确输入!';
          result.value = result;
          return result;
        }
        return result;
      },
      // 展示上一个结果
      showPrevResult: function(val) {
        prevResult.innerHTML = val || RESULT[RESULT.length - 1] || 0;
      },
      // 显示结果,并添加一个动画
      showResult: function(val) {
        var _this = this,
          rst = val || _this.getResult();

        RESULT.push(rst);
        result.style.animation = 'get-result .5s 1';

        setTimeout(function() {
          _this.deleteAll();
          _this.showPrevResult(val);
          result.style.animation = '';
        }, 500);
      },
      showExp: function(rst) {
        result.innerHTML = rst || expression.join('');
      },

    };
    // 将calculator.init和calculator.fn(calculator.prototype)联结
    calculator.fn.init.prototype = calculator.fn;

    return calculator();
  }

);

猜你喜欢

转载自blog.csdn.net/Char_n/article/details/81353508
今日推荐