为了账号安全,请及时绑定邮箱和手机立即绑定

使用 jQuery 动态创建按钮的问题

使用 jQuery 动态创建按钮的问题

温温酱 2022-12-22 13:41:58
我正在尝试将操作员按钮动态添加到我的计算器,但我只是运气不好。我已经创建了动态创建数字和操作员按钮的函数。数字已成功创建,但一旦我尝试添加运算符,就没有任何反应。我正在尝试使用 for-in 循环在我的括号按钮和求值按钮之间添加运算符。似乎当我在运算符之前创建评估按钮时,评估按钮已成功创建,但运算符却没有。如果我在评估按钮之前移动代码以创建运算符 ,则两者都不会出现。我相当确定问题出在我的 for-in 循环中,但我不太确定在哪里。非常感谢任何和所有帮助/指导! var opsData = {  add: {    precedence: 1,    name: 'add',    operation: function (a, b) {return a + b;},    output: function (a, b) {return a + ' + ' + b;},    buttonHTML: '+'  },  subtract: {    precedence: 1,    name: 'subtract',    operation: function (a, b) {return a - b;},    output: function (a, b) {return a + ' - ' + b;},    buttonHTML: '-'  },  multiply: {    precedence: 2,    name: 'multiply',    operation: function (a, b) {return a * b;},    output: function (a, b) {return a + ' * ' + b;},    buttonHTML: '*'  },  divide: {    precedence: 2,    name: 'divide',    operation: function (a, b) {return a / b;},    isInvalidInput: function (a, b) {return b == 0 ? 'division by 0' : false;},    output: function (a, b) {return a + ' / ' + b;},    buttonHTML: '/'  }}$.fn.addButton = function(html, className, onclick) {  $('<button />', {    html: html,    'class': 'button ' + className,    click: onclick    }).appendTo(this);  return this;}var addOperatorButton = function(op, click) {  $operators.addButton(op.buttonHTML, 'operator ' + op.name, function(e) {    click.call(this, e);    $currentCalc.text(inputStack.getCalculationString());    $collapsedCalc.text(inputStack.getCalculationString(true));    $input.text(inputStackgetPartialResult());    $input.data({clearOnInput: true});  });};var getInput = () => {  var input = $input.text();  return input.match(/error/i) ? 0 : parseFloat($input.text())}for (var i in opsData) {  (function(i) {    if (!opsData.buttonHTML[i]) return;    addOperatorButton(opsData[i], () => {      inputStack.push(getInput(), new Operation(opsData[i]));    })  }(i))}我的完整代码笔的链接在这里:https ://codepen.io/tazmancooks/pen/PoNwGMX如果我的问题没有得到很好的表达,我深表歉意,总的来说,我对 jQuery 和 Javascript 还是很陌生。
查看完整描述

2 回答

?
小怪兽爱吃肉

TA贡献1852条经验 获得超1个赞

您错误地访问了opsData对象:在第 352 行if (!opsData.buttonHTML[i]) return;更改为if (!opsData[i].buttonHTML) return;


按钮现在在那里,但您仍然需要更改 CSS。


$(function() {


  var opsData = {

    add: {

      precedence: 1,

      name: 'add',

      operation: function(a, b) {

        return a + b;

      },

      output: function(a, b) {

        return a + ' + ' + b;

      },

      buttonHTML: '+'

    },

    subtract: {

      precedence: 1,

      name: 'subtract',

      operation: function(a, b) {

        return a - b;

      },

      output: function(a, b) {

        return a + ' - ' + b;

      },

      buttonHTML: '-'

    },

    multiply: {

      precedence: 2,

      name: 'multiply',

      operation: function(a, b) {

        return a * b;

      },

      output: function(a, b) {

        return a + ' * ' + b;

      },

      buttonHTML: '*'

    },

    divide: {

      precedence: 2,

      name: 'divide',

      operation: function(a, b) {

        return a / b;

      },

      isInvalidInput: function(a, b) {

        return b == 0 ? 'division by 0' : false;

      },

      output: function(a, b) {

        return a + ' / ' + b;

      },

      buttonHTML: '/'

    }

  }


  var Operation = function(options) {

    var inputs = [];


    for (var key in options) {

      this[key] = options[key];

    };


    //Check if another input is needed, if not push current input to inputs array

    this.addInput = function(input) {

      if (this.isSaturated) return this;

      inputs.push(input)

      return this;

    }


    this.invalidInput = this.invalidInput || function() {

      return false;

    };


    //Check if operation already has all needed inputs

    this.isSaturated = () => {

      var inputCount = this.singleinput ? 1 : 2

      for (var i = 0; i < inputCount; i++) {

        if (inputs[i] === null || isNaN(inputs[i])) return false;

      }

      return true;

    }


    this.execute = () => {

      //If error is thrown, return

      if (this.error) return this;


      //Check if inputs are missing OR if operation was already executed

      if (!this.isSaturated || this.value != null) return this;


      //Map inputs to numerical values since inputs can also be operational objects [addition(1, multiplication(2, 3))]

      var inputValues = inputs.map(function(input) {

        return Number(input);

      });


      //Throw an error if there is invalid input

      this.error = this.isInvalidInput.apply(this, inputValues);

      if (this.error) {

        throw new Error(this.error);

      }


      this.calculationString = this.getCalculationString();

      this.value = this.operation.apply(this, inputValues);

      return this


    }


    this.getCalculationString = function(lastInput, collapsed) {

      if (collapsed) {

        this.execute();

        if (this.value != null) return this.value.toString();

      }


      var singleInput = this.singleInput;


      //Maps inputs to a string

      var inputValues = inputs.map(function(input) {

        var inputValue = input.getCalculationString ?

          input.getCalculationString(lastInput, collapsed) :

          input.toString();


        //Remove parenthases from any single input operations

        return singleInput ? inputValue.replace(/^\((.*)\)$/g, '$1') : inputValue;

      });

      return options.output.apply(this, inputValues.concat([lastInput]))

    }


    // Translate numerical value of the operation result

    // Execute operation if no result yet

    this.valueOf = () => {

      if (this.value == null) {

        this.execute()

      }

      return this.value

    }


    this.toString = () => {

      if (this.getCalculationString == null) {

        this.execute();

      }

      return this.getCalculationString();

    }


    var inputStack = (function() {

      var levels;


      var closedContext;


      var partialResult;


      var error;


      var Stack = function() {

        this.peek = function() {

          return this[this.length - 1];

        }

      };

      Stack.prototype = [];


      var reset = function() {

        levels = new Stack;

        levels.push(new Stack);

        closedContext = error = null

      };


      var wrapLastOperation = function(operation) {

        var stack = levels.peek();

        stack.push(operation.addInput(stack.pop()))

        collapse(operation.precedence)

      };


      var collapse = function(precedence) {

        var stack = levels.peek();

        var currentOperation = stack.pop();

        var previousOperation = stack.peek()


        if (!currentOperation) return;


        if (!currentOperation.isSaturated()) {

          stack.push(currentOperation);

          return;


          try {

            partialResult = Number(currentOperation);

          } catch (e) {

            partialResult = error = 'Error: ' + e.message;

          };


          if (previousOperation && previousOperation.precedence >= precedence) {

            previousOperation.addInput(currentOperation);

            collapse(precedence);

          } else {

            stack.push(currentOperation);

          }

        }

      };


      reset();


      return {

        push: function(number, operation) {

          //If an error already exists, reset

          error && reset();


          var stack = levels.peek();

          var lastOperation = stack.peek();


          var input = closedContext || number;

          closedContext = null


          partialResult = Number(input);


          if (!lastOperation || operation.precedence > lastoperation.precedence) {

            stack.push(operation.addInput(input))


            collapse(operation.precedence)

          } else {

            lastOperation.addInput(input);

            collapse(operation.precedence);

            wrapLastOperation(operation);

          }

          return this;

        },

        openContext: function() {

          error && reset();


          var lastOperation = levels.peek().peek();


          if (closedContext || lastOperation && lastOperation.isSaturated()) return


          //Opening new context means creating a new level to the stack

          levels.push(new Stack);


          return this;

        },

        closeContext: function(number) {

          error && reset();


          //If there's only one level, there's no need to close the context.

          if (levels.length <= 1) return;


          var inpute = closedContext || number


          //Grab last used operation

          var stack = levels.peek();

          var lastOperation = stack.peek()


          closedContext = new Operation(operationData.context).addInput(

            lastOperation ? (function() {

              lastOperation.addInput(input);

              collapse(0);

              return stack.pop();

            }()) :

            input

          )


          partialResult = Number(closedContext);


          levels.pop();

          return this;

        },

        evaluate: function(number) {

          error && reset();


          var input = closedContext || number


          //If no operator provided (just a number & '='), set result to the number.

          partialResult = Number(input);


          //If '=' is used without closing all parenthases, close the context.

          while (levels.length > 1) {

            this.closeContext(input)


            var lastOperation = levels.peek().peek();

            lastOperation && lastOperation.addInput(input);


            collapse(0);

            reset();


            return this;

          }

        },

        getPartialResult: function() {

          var _partialResult = partialResult;

          partialResult = 0;

          return _partialResult

        },

        getCalculationString: function(collapsed) {

          var result = closedContext ? closedContext.getCalculationString('', collapsed) : '';


          for (var i = levels.length - 1; i >= 0; i--) {

            for (var j = levels[i].length - 1; j >= 0; j--) {

              result = levels[i][j].getCalculationString(result, collapsed);

            }

            if (i > 0) {

              result = '(' + result;

            }

          }

          return result

        }

      }

    })


  }


  //Build calculator interface


  //Prototype for adding buttons

  $.fn.addButton = function(html, className, onclick) {

    $('<button />', {

      html: html,

      'class': 'button ' + className,

      click: onclick

    }).appendTo(this);

    return this;

  }


  var addNumberButton = function(num) {

    $numbers.addButton(num, 'number ' + (num === '.' ? 'dot' : 'number-' + num), () => {

      if ($input.text().match(/\./) && num == '.') return;

      if ($input.text() == 0 && num != '.' || $input.data('clearOnInput')) {

        $input.text('');

      }

      $input.data({

        clearOnInput: false

      });

      $input.text($input.text() + $(this).text());

    })

  };


  var addOperatorButton = function(op, click) {

    $operators.addButton(op.buttonHTML, 'operator ' + op.name, function(e) {

      click.call(this, e);

      $currentCalc.text(inputStack.getCalculationString());

      $collapsedCalc.text(inputStack.getCalculationString(true));

      $input.text(inputStackgetPartialResult());

      $input.data({

        clearOnInput: true

      });

    });

  };


  var getInput = () => {

    var input = $input.text();

    return input.match(/error/i) ? 0 : parseFloat($input.text())

  }


  var $calculator = $('#calculator');

  var $calcDisplay = $('<div/>', {

    'class': 'calcDisplay'

  }).appendTo($calculator);

  var $currentCalc = $('<div/>', {

    'class': 'currentCalc'

  }).appendTo($calcDisplay);

  var $collapsedCalc = $('<div/>', {

    'class': 'collapsedCalc'

  }).appendTo($calcDisplay);

  var $input = $('<div/>', {

    'class': 'input'

  }).appendTo($calcDisplay);

  var $numbers = $('<div/>', {

    'class': 'numbers'

  }).appendTo($calculator);

  var $operators = $('<div/>', {

    'class': 'operators'

  }).appendTo($calculator);


  $numbers.addButton('del', 'del', () => {

    $input.text($input.text().replace(/.$/, ''))

  })


  $numbers.addButton('CE', 'clear-entry', () => {

    $input.text('0')

  })


  $numbers.addButton('C', 'clear')


  $.each('7894561230.'.split(''), (itm, value) => {

    addNumberButton(value)

  });


  addOperatorButton({

    buttonHTML: '(',

    name: 'openContext'

  }, () => {

    inputStack.openContext();

  });


  addOperatorButton({

    buttonHTML: ')',

    name: 'closeContext'

  }, () => {

    inputStack.closeContext(getInput());

  });



  for (var i in opsData) {

    (function(i) {

      if (!opsData[i].buttonHTML) return;

      addOperatorButton(opsData[i], () => {

        inputStack.push(getInput(), new Operation(opsData[i]));

      })

    }(i))

  }


  addOperatorButton({

    buttonHTML: '=',

    name: 'evaluate'

  }, () => {

    inputStack.evaluate(getInput());

  });

});

html,

body {

  background-color: black;

}


#calculator {

  background-color: grey;

  width: 250px;

  padding-top: 20px;

  padding-bottom: 30px;

  border-bottom-right-radius: 2em;

  border-bottom-left-radius: 2em;

  margin-right: auto;

  margin-left: auto;

  overflow: auto;

}


.calcDisplay {

  border: 1px solid;

  height: 50px;

  margin: 4px;

  padding: 2px;

  text-align: right;

  overflow: hide;

  position: relative;

  background: white;

}


.button {

  width: 60px;

  height: 60px;

  padding: 0px;

  line-height: 30px;

  text-align: center;

  border: 1px solid;

  cursor: pointer;

  float: left;

  margin: 4px;

  border-radius: 50%;

}


.number {

  background: #fff;

}


.number-0 {

  width: 129px;

}

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id='calculator'></div>


查看完整回答
反对 回复 2022-12-22
?
幕布斯6054654

TA贡献1876条经验 获得超7个赞

问题是当您尝试循环遍历 opsData 对象时。


for (var i in opsData) {

  (function(i) {

    if (!opsData.buttonHTML[i]) return;

      addOperatorButton(opsData[i], () => {

      inputStack.push(getInput(), new Operation(opsData[i]));

    })

  }(i))

}

当您应该访问 opsData[i].buttonHTML 时,您正在访问 buttonHTML 的 [i] 属性


查看完整回答
反对 回复 2022-12-22
  • 2 回答
  • 0 关注
  • 128 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号