使用javascript添加并获得用户从动态文本框输入的值的平均值

add and get the average of values inputted by user from dynamic textboxes using javascript

本文关键字:文本 输入 动态 平均值 添加 javascript 用户 使用      更新时间:2023-09-26

我有5个文本框显示,用户可以动态添加更多的文本框。但是,我无法获得用户在这些文本框上输入的值的总和和平均值。你能帮帮我吗?我真的很感激。

下面是HTML代码:

    <html>
    <head>
    <title> Grading System </title>
    </head>
    <script src="addInput.js" language="Javascript" type="text/javascript">
        </script>                             
        <body>
        <center> GRADING SYSTEM <br><br>
<form method="POST">
    <div id="dynamicInput">
    Subject number 1<br><input type="text" name="myInputs[]"><br>
    Subject number 2<br><input type="text" name="myInputs[]"><br>
    Subject number 3<br><input type="text" name="myInputs[]"><br>
    Subject number 4<br><input type="text" name="myInputs[]"><br>
    Subject number 5<br><input type="text" name="myInputs[]">   
    </div>
<input type="button" value="Add a subject" onClick="addInput('dynamicInput');">
<input type="button" name="BtnCompute" onClick="avg('dynamicInput');" value="Compute Average">
</form>
</body>
</html>

Javascript代码:

var counter = 5;
var limit = 10;
var sum=0;
var average=0;

function addInput(divName){
     if (counter == limit)  {
          alert("You have reached the limit of adding " + counter + " inputs");
     }
     else {
          var newdiv = document.createElement('div');
          newdiv.innerHTML = "Subject number " + (counter + 1) + " <br><input type='text' name='myInputs[]' >";
          document.getElementById(divName).appendChild(newdiv);
         counter++

     } 
}
function avg(divName){
sum += document.getElementsByName("myInputs[]")[0].value;
average = sum / counter
alert("Average is " + average);   
return false;
}

原函数的问题:

function avg(divName) {
    // you only look at one <input> element ever time, rather
    // than iterating over the collection returned by
    // 'document.getElementsByName("myInputs[]")'; plus you're using
    // a global value which is (at least potentially) exposed to
    // every other function, which makes it vulnerable to being
    // over-written by other values; also: you're not ensuring that
    // the entered-value is a Number (an <input> returns its value as
    // a String, not a Number):
    sum += document.getElementsByName("myInputs[]")[0].value;
    // here you're working out the average of two global values,
    // both of which could be corrupted by other functions, and
    // neither of which - being global - are guaranteed to be
    // Numbers, since you're not enforcing that anywhere. Also
    // you've exposed yourself to potential browser interference
    // by not ending the line with the (optional) semi-colon:
    average = sum / counter
    // this is personal, but for debugging I'd recommend use of
    // console.log() (but, again, a purely personal reccomendation
    // and not really a 'problem' as such):
    alert("Average is " + average);
    return false;
}

我对你原来的功能的更正是:

function avg() {
    // rather than passing in an argument explicitly, I've opted
    // to use a custom data-* attribute to contain the id of the
    // relevant <div> (see the HTML below, this simplifies
    // changes somewhat in the future):
    var div = document.getElementById(this.dataset.divname),
    // using Node.querySelectorAll() to retrieve the relevant
    // <input> elements (my inclination would be to further
    // amend the selector to 'input,' but that depends on
    // whether or not you'd have any irrelevant <input>
    // elements contained within the same <div>):
        inputs = div.querySelectorAll('input[type=text][name="myInputs[]"]'),
    // using Function.prototype.call() to apply the
    // Array.prototoype.map() function to the Array-like
    // NodeList returned by document.querySelectorAll(),
    // and returns an Array of (in this case) entered values:
        sum = Array.prototype.map.call(inputs, function (inputNode) {
            // here we convert the existing value of the <input>
            // element-node to a Number (<input> elements return
            // their values as a String) or, if the value can't
            // be converted to a Number, or the <input> has no
            // entered value, we return 0:
            return parseFloat(inputNode.value) || 0;
        // using Array.prototype.reduce() to sum the
        // Array of values returned by Array.prototype.map():
        }).reduce(function (a, b) {
            // here we return the sum of the previous number
            // and the current number:
            return a + b;
        // the 0 here is the initial starting value
        // to which the numbers are added:
        }, 0),
        // ensuring that the counter variable (first
        // argument) is parsed into an integer value
        // (using parseInt(), in base-10 (the second
        // argument):
        average = sum / parseInt(counter, 10);
    console.log("Average is " + average);
    return false;
}
// here we use JavaScript to attach the event-handling function to
// the relevant <input> (I added the 'id' to enable this), and
// this binds the avg() function to handle the 'click' event:
document.getElementById('btnCompute').addEventListener('click', avg);

修改后的<input>元素HTML:

<input id="btnCompute" data-divname="dynamicInput" type="button" name="BtnCompute" value="Compute Average" />

var counter = 5;
var limit = 10;
function addInput() {
  // note that I've amended this function also, to
  // use the 'data-divname' attribute to hold the
  // 'id' of the relevant <div>:
  var div = document.getElementById(this.dataset.divname);
  if (counter == limit) {
    alert("You have reached the limit of adding " + counter + " inputs");
  } else {
    var newdiv = document.createElement('div');
    newdiv.innerHTML = "Subject number " + (counter + 1) + " <br><input type='text' name='myInputs[]' >";
    div.appendChild(newdiv);
    counter++
  }
}
function avg() {
  var div = document.getElementById(this.dataset.divname),
    inputs = div.querySelectorAll('input[type=text][name="myInputs[]"]'),
    sum = Array.prototype.map.call(inputs, function(inputNode) {
      return parseFloat(inputNode.value) || 0;
    }).reduce(function(a, b) {
      return a + b;
    }, 0),
    average = sum / parseInt(counter, 10);
  snippet.log("Average is " + average);
  return false;
}
document.getElementById('addNew').addEventListener('click', addInput);
document.getElementById('btnCompute').addEventListener('click', avg);
label,
input[type=text] {
  display: block;
}
<!-- Provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
<!--
     Note that I've also amended your HTML, removing the
     unnecessary <br /> elements, instead using CSS to
     provide line-breaks; and also wrapping the <input>
     elements in <labels>, both to enable the CSS line-
     breaks and to enable clicks on the text to focus
     the associated (nested) <input> element:
-->
<form method="POST" action="#">
  <div id="dynamicInput">
    <label>Subject number 1
      <input type="text" name="myInputs[]" />
    </label>
    <label>Subject number 2
      <input type="text" name="myInputs[]" />
    </label>
    <label>Subject number 3
      <input type="text" name="myInputs[]" />
    </label>
    <label>Subject number 4
      <input type="text" name="myInputs[]" />
    </label>
    <label>Subject number 5
      <input type="text" name="myInputs[]" />
    </label>
  </div>
  <input id="addNew" data-divname="dynamicInput" type="button" value="Add a subject" />
  <input id="btnCompute" data-divname="dynamicInput" type="button" name="BtnCompute" value="Compute Average" />

外部JS demo,用于实验/开发。

尽管我纠正了你的功能,但我可能会采取另一种方法:

// because I retrieve the number of elements in a couple
// of places, I created a simple function to retrieve
// that number of elements:
function currentlyExisting(selector) {
    return document.querySelectorAll(selector).length;
}
// rewritten in my own style (though this is irrelevant to the
// the question you asked):
function addNew() {
    // still using the value of the custom 'data-divname'
    // attribute:
    var parent = document.getElementById(this.dataset.divname),
    // rather than creating a HTML string, here I create nodes
    // using document.createElement() and a textNode, using
    // document.createTextNode():
        label = document.createElement('label'),
        input = document.createElement('input'),
     // getting the number of currently-existing <input>
     // elements using the above function, passing the
     // selector as an argument:
        current = currentlyExisting('input[name="myInputs[]"'),
        limit = 10;
    // if the current number of <input> elements is less than
    // the limit:
    if (current < limit) {
        // we set the type of the created <input>:
        input.type = 'text';
        // and the name property:
        input.name = 'myInputs[]';
        // appending a textNode to the created <label> element:
        label.appendChild(document.createTextNode('Subject number ' + (current + 1) + ':' ));
        // appending the created <input> to the created <label>:
        label.appendChild(input);
        // attaching the created <label>, along with its own
        // childNodes, to the parent div (retrieved and cached above):
        parent.appendChild(label);
        // setting the disabled property to true if the updated
        // number of <input> elements is equal to, or greater than,
        // the limit; or to false if the number of <input> elements
        // remains less than the limit (preventing the addition of
        // more <input> elements than that identified by the limit):
        this.disabled = currentlyExisting('input[name="myInputs[]"') >= limit;
    }
    // all functions return a value, whether it's explicitly defined
    // or undefined (as this one will), the return false of your
    // original function can be added here instead if you prefer,
    // but I - personally - feel it's unnecessary, so I left it out.
}
function average() {
    // retrieving the relevant <div> element using the
    // data-divname attribute once again:
    var parent = document.getElementById(this.dataset.divname),
        // retrieving the relevant <input> elements:
        inputs = parent.querySelectorAll('input[name="myInputs[]"]'),
        // creating an Array of the values of the relevant
        // <input> elements, using Function.prototype.call()
        // in order to use Array.prototype.map() on the
        // Array-like NodeList returned by querySelectorAll():
        values = Array.prototype.map.call(inputs, function (input) {
            // returning the value of the current <input>
            // element as a number to the array, using
            // parseFloat() to convert that String to a
            // Number; or returning 0 if the String cannot
            // be parsed as a Number:
            return parseFloat(input.value) || 0;
        // using Array.prototype.reduce() to reduce the Array
        // of numeric values (provided by map()) to a single
        // number, the sum of the values:
        }).reduce(function (a, b) {
            // adding the previous and current values
            // together:
            return a + b;
        // here the 0 is the initial value before the Array
        // 'reduction' takes place:
        }, 0),
        average = sum / inputs.length;
    // adding the values to the appropriate elements on screen
    // for easier visualisation (and in a manner that persists):
    document.getElementById('average').textContent = average;
    document.getElementById('sum').textContent = sum;
    document.getElementById('total').textContent = inputs.length;
}
// adding the click event handlers to the relevant button <input>
// elements using EventTarget.addEventListener():
document.getElementById('addNew').addEventListener('click', addNew);
document.getElementById('btnCompute').addEventListener('click', average);

function currentlyExisting(selector) {
  return document.querySelectorAll(selector).length;
}
function addNew() {
  var parent = document.getElementById(this.dataset.divname),
    label = document.createElement('label'),
    input = document.createElement('input'),
    current = currentlyExisting('input[name="myInputs[]"'),
    limit = 10;
  if (current < limit) {
    input.type = 'text';
    input.name = 'myInputs[]';
    label.appendChild(document.createTextNode('Subject number ' + (current + 1) + ':'));
    label.appendChild(input);
    parent.appendChild(label);
    this.disabled = currentlyExisting('input[name="myInputs[]"') >= limit;
  }
}
function average() {
  var parent = document.getElementById('dynamicInput'),
    inputs = parent.querySelectorAll('input[name="myInputs[]"]'),
    sum = Array.prototype.map.call(inputs, function(input) {
      return parseFloat(input.value) || 0;
    }).reduce(function(a, b) {
      return a + b;
    }, 0),
    average = sum / inputs.length;
  document.getElementById('average').textContent = average;
  document.getElementById('sum').textContent = sum;
  document.getElementById('total').textContent = inputs.length;
}
document.getElementById('addNew').addEventListener('click', addNew);
document.getElementById('btnCompute').addEventListener('click', average);
label,
input[type=text] {
  display: block;
}
#average::before {
  content: 'Average: ';
}
#sum::before {
  content: ', sum: ';
}
#total::before {
  content: ', of: ';
}
#total::after {
  content: ' entries.'
}
#total:empty::before,
#total:empty::after,
#sum:empty::before,
#average:empty::before {
  content: '';
  display: none;
}
<div id="results">
  <span id="average"></span>
  <span id="sum"></span>
  <span id="total"></span>
</div>
<form method="POST" action="#">
  <div id="dynamicInput">
    <label>Subject number 1:
      <input type="text" name="myInputs[]" />
    </label>
    <label>Subject number 2:
      <input type="text" name="myInputs[]" />
    </label>
    <label>Subject number 3:
      <input type="text" name="myInputs[]" />
    </label>
    <label>Subject number 4:
      <input type="text" name="myInputs[]" />
    </label>
    <label>Subject number 5:
      <input type="text" name="myInputs[]" />
    </label>
  </div>
  <input id="addNew" data-divname="dynamicInput" type="button" value="Add a subject" />
  <input id="btnCompute" data-divname="dynamicInput" type="button" name="BtnCompute" value="Compute Average" />
</form>

外部JS demo,用于实验/开发。

引用

  • HTML:
    • 自定义data-*属性。
  • JavaScript:
    • Array.prototype.map() .
    • Array.prototype.reduce() .
    • document.getElementById() .
    • document.getElementsByName() .
    • document.querySelectorAll() .
    • EventTarget.addEventListener() .
    • Function.prototype.call() .
    • HTMLElement.dataset .
    • parseFloat() .
    • parseInt() .

所以我认为你错过了一些东西。

sum += document.getElementsByName("myInputs[]")[0].value;

这一行只获取第一个输入字段的值,因此需要循环遍历所有输入字段以获得实际的和

for (var i = 0; i < counter; i++)
    sum += parseInt(document.getElementsByName("myInputs[]")[i].value);

接下来,注意parseInt();方法的添加。这会将输入值(javascript默认将其视为字符串)转换为可以执行计算的整数。

希望对你有帮助,谢谢