我的学生每学期至少需要学习一门科学,一门物理和一门历史考试。下面的表格给出了正确的平均成绩以及学生的最终成绩:
document.getElementById('calcBtn').addEventListener('click', function() {
var scienceTest1 = document.getElementById('scienceTest1').value;
var scienceTest2 = document.getElementById('scienceTest2').value;
var scienceTest3 = document.getElementById('scienceTest3').value;
var physicsTest1 = document.getElementById('physicsTest1').value;
var physicsTest2 = document.getElementById('physicsTest2').value;
var physicsTest3 = document.getElementById('physicsTest3').value;
var historyTest1 = document.getElementById('historyTest1').value;
var historyTest2 = document.getElementById('historyTest2').value;
var historyTest3 = document.getElementById('historyTest3').value;
var scienceAverage = document.getElementById('scienceAverage');
var physicsAverage = document.getElementById('physicsAverage');
var historyAverage = document.getElementById('historyAverage');
var finalGrade = document.getElementById('finalGrade');
scienceAverage.value = (Number(scienceTest1) + Number(scienceTest2) + Number(scienceTest3)) / 3;
physicsAverage.value = (Number(physicsTest1) + Number(physicsTest2) + Number(physicsTest3)) / 3;
historyAverage.value = (Number(historyTest1) + Number(historyTest2) + Number(historyTest3)) / 3;
finalGrade.value = (scienceAverage.value * 5 + physicsAverage.value * 3 + historyAverage.value * 2) / 10;
});
<form>
Science: <input type="number" id="scienceTest1">
<input type="number" id="scienceTest2">
<input type="number" id="scienceTest3">
<output id="scienceAverage"></output>
<br> Physics: <input type="number" id="physicsTest1">
<input type="number" id="physicsTest2">
<input type="number" id="physicsTest3">
<output id="physicsAverage"></output>
<br> History: <input type="number" id="historyTest1">
<input type="number" id="historyTest2">
<input type="number" id="historyTest3">
<output id="historyAverage"></output>
<br>
<input type="button" value="Calculate" id="calcBtn">
<output id="finalGrade"></output>
</form>
问题在于,只有在所有字段都被编辑的情况下,它才有效。如果学生不参加某些考试,平均成绩将不会显示正确的值。我知道这是因为在计算平均成绩时会除以固定数字3
:
scienceAverage.value = (Number(scienceTest1) + Number(scienceTest2) + Number(scienceTest3)) / 3;
physicsAverage.value = (Number(physicsTest1) + Number(physicsTest2) + Number(physicsTest3)) / 3;
historyAverage.value = (Number(historyTest1) + Number(historyTest2) + Number(historyTest3)) / 3;
在下面的单行中获取已更改输入字段数的简单方法是什么?我将尝试了解您的方法,然后将表单扩展为多行。
document.getElementById('calcBtn').addEventListener('click', function() {
var test1 = document.getElementById('test1').value;
var test2 = document.getElementById('test2').value;
var test3 = document.getElementById('test3').value;
var average = document.getElementById('average');
average.value = (Number(test1) + Number(test2) + Number(test3)) / 3;
});
<form>
<input type="number" id="test1">
<input type="number" id="test2">
<input type="number" id="test3">
<output id="average"></output>
<br>
<input type="button" value="Calculate" id="calcBtn">
</form>
答案 0 :(得分:17)
您似乎需要检查输入的值是否为有效数字,然后才能在计算每门课程平均值的算术中使用它们。一种方法是通过以下检查:
if (!Number.isNaN(Number.parseFloat(input.value))) {
/* Use input.value in average calculation */
}
您还可以考虑如下所示调整脚本和HTML,这将使您能够概括并重新使用这三个类的平均值计算,如下所述:
document.getElementById('calcBtn').addEventListener('click', function() {
/* Generalise the calculation of updates for specified course type */
const calculateForCourse = (cls) => {
let total = 0
let count = 0
/* Select inputs with supplied cls selector and iterate each element */
for (const input of document.querySelectorAll(`input.${cls}`)) {
if (!Number.isNaN(Number.parseFloat(input.value))) {
/* If input value is non-empty, increment total and count for
subsequent average calculation */
total += Number.parseFloat(input.value);
count += 1;
}
}
/* Cacluate average and return result */
return { count, average : count > 0 ? (total / count) : 0 }
}
/* Calculate averages using shared function for each class type */
const calcsScience = calculateForCourse('science')
const calcsPhysics = calculateForCourse('physics')
const calcsHistory = calculateForCourse('history')
/* Update course averages */
document.querySelector('output.science').value = calcsScience.average
document.querySelector('output.physics').value = calcsPhysics.average
document.querySelector('output.history').value = calcsHistory.average
/* Update course counts */
document.querySelector('span.science').innerText = `changed:${calcsScience.count}`
document.querySelector('span.physics').innerText = `changed:${calcsPhysics.count}`
document.querySelector('span.history').innerText = `changed:${calcsHistory.count}`
/* Update final grade */
var finalGrade = document.getElementById('finalGrade');
finalGrade.value = (calcsScience.average * 5 + calcsPhysics.average * 3 + calcsHistory.average * 2) / 10;
});
<!-- Add class to each of the course types to allow script to distinguish
between related input and output fields -->
<form>
Science:
<input type="number" class="science" id="scienceTest1">
<input type="number" class="science" id="scienceTest2">
<input type="number" class="science" id="scienceTest3">
<output id="scienceAverage" class="science"></output>
<span class="science"></span>
<br> Physics:
<input type="number" class="physics" id="physicsTest1">
<input type="number" class="physics" id="physicsTest2">
<input type="number" class="physics" id="physicsTest3">
<output id="physicsAverage" class="physics"></output>
<span class="physics"></span>
<br> History:
<input type="number" class="history" id="historyTest1">
<input type="number" class="history" id="historyTest2">
<input type="number" class="history" id="historyTest3">
<output id="historyAverage" class="history"></output>
<span class="history"></span>
<br>
<input type="button" value="Calculate" id="calcBtn">
<output id="finalGrade"></output>
</form>
要扩展第一个答案,请参阅以下代码段中的文档以回应您的问题更新:
document.getElementById('calcBtn').addEventListener('click', function() {
var test1 = document.getElementById('test1').value;
var test2 = document.getElementById('test2').value;
var test3 = document.getElementById('test3').value;
var average = document.getElementById('average');
/* This variable counts the number of inputs that have changed */
var changesDetected = 0;
/* If value of test1 field "not equals" the empty string, then
we consider this a "changed" field, so we'll increment our
counter variable accordinly */
if(test1 != '') {
changesDetected = changesDetected + 1;
}
/* Apply the same increment as above for test2 field */
if(test2 != '') {
changesDetected = changesDetected + 1;
}
/* Apply the same increment as above for test3 field */
if(test3 != '') {
changesDetected = changesDetected + 1;
}
/* Calculate average from changesDetected counter.
We need to account for the case where no changes
have been detected to prevent a "divide by zero" */
if(changesDetected != 0) {
average.value = (Number(test1) + Number(test2) + Number(test3)) / changesDetected;
}
else {
average.value = 'Cannot calculate average'
}
/* Show a dialog to box to display the number of fields changed */
alert("Detected that " + changesDetected + " inputs have been changed")
});
<form>
<input type="number" id="test1">
<input type="number" id="test2">
<input type="number" id="test3">
<output id="average"></output>
<br>
<input type="button" value="Calculate" id="calcBtn">
</form>
可以使用如下循环简化先前的更新:
document.getElementById('calcBtn').addEventListener('click', function() {
let changesDetected = 0;
let total = 0;
const ids = ['test1', 'test2', 'test3'];
for(const id of ids) {
const value = document.getElementById(id).value;
if(value != '') {
changesDetected += 1;
total += Number(value);
}
}
var average = document.getElementById('average');
if(changesDetected != 0) {
average.value = total / changesDetected;
}
else {
average.value = 'Cannot calculate average'
}
alert("Detected that " + changesDetected + " inputs have been changed")
});
<form>
<input type="number" id="test1">
<input type="number" id="test2">
<input type="number" id="test3">
<output id="average"></output>
<br>
<input type="button" value="Calculate" id="calcBtn">
</form>
另一种简洁的方法based on your JSFiddle是:
document.getElementById('calculator').addEventListener('click', function() {
var physicsAverage = document.getElementById('physicsAverage'),
historyAverage = document.getElementById('historyAverage');
physicsAverage.value = calculateAverageById('physics')
historyAverage.value = calculateAverageById('history');
});
function calculateAverageById(id) {
/* Get all input descendants of element with id */
const inputs = document.querySelectorAll(`#${id} input`);
/* Get all valid grade values from selected input elements */
const grades = Array.from(inputs)
.map(input => Number.parseFloat(input.value))
.filter(value => !Number.isNaN(value));
/* Return average of all grades, or fallback message if no valid grades present */
return grades.length ? (grades.reduce((sum, grade) => (sum + grade), 0) / grades.length) : 'No assessment made!'
}
<form>
<p id="physics">
Physics:
<input type="number">
<input type="number">
<input type="number">
<output id="physicsAverage"></output>
</p>
<p id="history">
History:
<input type="number">
<input type="number">
<input type="number">
<output id="historyAverage"></output>
</p>
<button type="button" id="calculator">Calculate</button>
</form>
这里的主要区别是:
document.querySelectorAll(
#$ {id}输入);
和模板文字来提取具有input
的元素的id
元素Array.from(inputs)
用于将查询结果转换为数组的更易读的方式Number.parseFloat
元素转换和过滤为有效数值以进行后续平均计算时,使用Number.isNaN
和input
希望有帮助!
答案 1 :(得分:7)
一个好的开始是将您的ID更改为Class,以将您的输入放入逻辑组。下一步是从值不为null的特定组中获取输入。为此,我们可以选择例如.scienceTest
,然后过滤掉空字符串项目。
我添加了一个辅助函数values
,以从节点列表中提取值并将其放入普通数组中。
我们可以使用Boolean
测试空字符串。我们还使用Number
将所有字符串都转换为数字。这是在onlyNumbers
函数中完成的。
接下来,我们需要计算每个组的平均值。这很容易,因为我们有一个过滤的数字列表。我们要做的就是计算总和并除以数组长度。这是通过我们小的avrg
函数完成的。
document.getElementById('calcBtn').addEventListener('click', function() {
var scienceTest = getGrades('.scienceTest')
var physicsTest = getGrades('.physicsTest')
var historyTest = getGrades('.historyTest')
var scienceAverage = document.getElementById('scienceAverage');
var physicsAverage = document.getElementById('physicsAverage');
var historyAverage = document.getElementById('historyAverage');
var finalGrade = document.getElementById('finalGrade');
scienceAverage.value = avrg(scienceTest)
physicsAverage.value = avrg(physicsTest)
historyAverage.value = avrg(historyTest)
finalGrade.value = (scienceAverage.value * 5 + physicsAverage.value * 3 + historyAverage.value * 2) / 10;
});
function avrg(list) {
return list.length ? list.reduce((acc, i) => acc + i, 0) / list.length : 0
}
function getGrades(selector) {
return onlyNumbers(values(document.querySelectorAll(selector)))
}
function onlyNumbers(list) {
return list.filter(Boolean).map(Number)
}
function values(nodelist) {
return Array.prototype.map.call(nodelist, (node) => node.value)
}
<form>
Science: <input type="number" class="scienceTest">
<input type="number" class="scienceTest">
<input type="number" class="scienceTest">
<output id="scienceAverage"></output>
<br> Physics: <input type="number" class="physicsTest">
<input type="number" class="physicsTest">
<input type="number" class="physicsTest">
<output id="physicsAverage"></output>
<br> History: <input type="number" class="historyTest">
<input type="number" class="historyTest">
<input type="number" class="historyTest">
<output id="historyAverage"></output>
<br>
<input type="button" value="Calculate" id="calcBtn">
<output id="finalGrade"></output>
</form>
更新:简化示例
document.getElementById('calcBtn').addEventListener('click', function() {
var test1 = document.getElementById('test1').value;
var test2 = document.getElementById('test2').value;
var test3 = document.getElementById('test3').value;
var average = document.getElementById('average');
// Put all field values in array, Filter empty values out, cast values to Number
var rowValues = [test1, test2, test3].filter(Boolean).map(Number)
console.log('Number of changed fields', rowValues.length)
// calculate average by reducing the array to the sum of its remaining values then divide by array length
average.value = rowValues.reduce((sum, grade) => sum + grade, 0) / rowValues.length;
});
<form>
<input type="number" id="test1">
<input type="number" id="test2">
<input type="number" id="test3">
<output id="average"></output>
<br>
<input type="button" value="Calculate" id="calcBtn">
</form>
更新其他内容:基于OP的jsfiddle示例中的注释
document.getElementById('calculator').addEventListener('click', function() {
var physicsAverage = document.getElementById('physicsAverage'),
historyAverage = document.getElementById('historyAverage');
physicsAverage.value = calculateAverageById('physics')
historyAverage.value = calculateAverageById('history');
});
function calculateAverageById(id) {
// Get all inputs under Id
var inputs = document.getElementById(id).getElementsByTagName('input')
var values =
Array.prototype.slice.call(inputs) // From HTMLCollection to Array
.map(e => e.value.trim()) // Return all .value from input elements
.filter(Boolean) // Filter out any empty strings ""
.map(Number) // convert remaining values to Numbers
return (values.length) ? // if length is greater then 0
values.reduce((sum, grade) => sum + grade, 0) / values.length // Return average
:
'No assessment made!' // else return this message
}
<form>
<p id="physics">
Physics:
<input type="number">
<input type="number">
<input type="number">
<output id="physicsAverage"></output>
</p>
<p id="history">
History:
<input type="number">
<input type="number">
<input type="number">
<output id="historyAverage"></output>
</p>
<button type="button" id="calculator">Calculate</button>
</form>
答案 2 :(得分:5)
您不必一直将其除以3,而是可以根据学生连续更新的输入字段数来动态计算该数字。
这是工作代码:
function getValueAndTotal(element){
var valueChanged = (element.defaultValue === element.value || element.value === "") ? 0 : 1;
return { value: Number(element.value), total: valueChanged };
}
document.getElementById('calcBtn').addEventListener('click', function() {
var scienceTest1 = getValueAndTotal(document.getElementById('scienceTest1'));
var scienceTest2 = getValueAndTotal(document.getElementById('scienceTest2'));
var scienceTest3 = getValueAndTotal(document.getElementById('scienceTest3'));
var physicsTest1 = getValueAndTotal(document.getElementById('physicsTest1'));
var physicsTest2 = getValueAndTotal(document.getElementById('physicsTest2'));
var physicsTest3 = getValueAndTotal(document.getElementById('physicsTest3'));
var historyTest1 = getValueAndTotal(document.getElementById('historyTest1'));
var historyTest2 = getValueAndTotal(document.getElementById('historyTest2'));
var historyTest3 = getValueAndTotal(document.getElementById('historyTest3'));
var scienceAverage = document.getElementById('scienceAverage');
var physicsAverage = document.getElementById('physicsAverage');
var historyAverage = document.getElementById('historyAverage');
var finalGrade = document.getElementById('finalGrade');
var scienceTotalTests = scienceTest1.total + scienceTest2.total + scienceTest3.total;
var physicsTotalTests = physicsTest1.total + physicsTest2.total + physicsTest3.total;
var historyTotalTests = historyTest1.total + historyTest2.total + historyTest3.total;
scienceAverage.value = (scienceTotalTests === 0 ? 0 : (scienceTest1.value + scienceTest2.value + scienceTest3.value) / scienceTotalTests);
physicsAverage.value = (physicsTotalTests === 0 ? 0 : (physicsTest1.value + physicsTest3.value + physicsTest3.value) / physicsTotalTests);
historyAverage.value = (historyTotalTests === 0 ? 0 : (historyTest1.value + historyTest2.value + historyTest3.value) / historyTotalTests);
finalGrade.value = (scienceAverage.value * 5 + physicsAverage.value * 3 + historyAverage.value * 2) / 10;
});
<form>
Science:
<input type="number" id="scienceTest1" class="scienceTest">
<input type="number" id="scienceTest2" class="scienceTest">
<input type="number" id="scienceTest3" class="scienceTest">
<output id="scienceAverage"></output>
<br>Physics:
<input type="number" id="physicsTest1">
<input type="number" id="physicsTest2">
<input type="number" id="physicsTest3">
<output id="physicsAverage"></output>
<br>History:
<input type="number" id="historyTest1">
<input type="number" id="historyTest2">
<input type="number" id="historyTest3">
<output id="historyAverage"></output>
<br>
<input type="button" value="Calculate" id="calcBtn">
<output id="finalGrade"></output>
</form>
答案 3 :(得分:5)
这有点丑陋,但您可以将测试成绩视为布尔值:如果有任何测试成绩的价值为1,否则为0。
由于input.value
的类型为string
,因此当输入为空(false
)或{{1}时,将其转换为布尔值将得到""
}(其中有数字)。
使用OP的较小代码段:
true
document.getElementById('calcBtn').addEventListener('click', function() {
var test1 = document.getElementById('test1').value;
var test2 = document.getElementById('test2').value;
var test3 = document.getElementById('test3').value;
var testCount = Boolean(test1) + Boolean(test2) + Boolean(test3);
// alternatively: var testCount = !!test1 + !!test2 + !!test3
var average = document.getElementById('average');
average.value = (Number(test1) + Number(test2) + Number(test3)) / testCount;
});
答案 4 :(得分:4)
您需要注意代码中的两个主要瓶颈:
value
,则仅要考虑该主题。在这种情况下,0
将被计数,但空白字段将不会被计数(因为从技术上讲,学生可以在他/她的考试中获得0分)我没有尝试修改您拥有的代码,而是实际上重构了逻辑,以便根据DRY(不重复自己)原理将所有计算抽象为函数。这些功能是:
calculateSubjectAverage
,它计算给定主题的正确平均值。它将考虑0
,但忽略空字段setSubjectAverage
,它将设置适当的<output>
元素最后,您不必手动计算加权平均值,而可以轻松地将所有元数据存储在对象数组中,例如:
var subjects = [{
name: 'science',
weight: 5
}, {
name: 'physics',
weight: 3
}, {
name: 'history',
weight: 2
}];
这使我们可以过滤subjects
并计算其正确的加权和,从而计算出加权平均值。需要进行过滤,因为全空主题得分有可能返回undefined
。
请参见下面的概念验证:
function calculateSubjectAverage(className) {
var inputs = document.querySelectorAll('.' + className);
var scores = Array.prototype.map.call(inputs, function(input) {
if (input.value === '')
return;
return +input.value;
});
var count = 0;
var scoreSum = scores.reduce(function(acc, score) {
if (isNaN(score))
return acc;
count++;
return acc + score;
}, 0);
return scoreSum / count;
};
function setSubjectAverage(className, averageScore) {
if (isNaN(averageScore))
return;
document.getElementById(className + 'Average').value = averageScore;
}
document.getElementById('calcBtn').addEventListener('click', function() {
var subjects = [{
name: 'science',
weight: 5
}, {
name: 'physics',
weight: 3
}, {
name: 'history',
weight: 2
}];
var totalWeight = 0;
// Go through each subject and calculate & set average score
// Since we are iterating anyway, might want to calculate totalWeight, too
subjects.forEach(function(subject) {
var averageScore = calculateSubjectAverage(subject.name);
setSubjectAverage(subject.name, averageScore);
// Set average score to object
subject.average = averageScore;
if (!isNaN(averageScore))
totalWeight += subject.weight;
});
// Only compute weighted average from subject with valid averages
var weightedTotal = subjects.reduce(function(acc, subject) {
if (isNaN(subject.average))
return acc;
return acc + subject.average * subject.weight;
}, 0);
var weightedAverage = weightedTotal / totalWeight;
if (!isNaN(weightedTotal / totalWeight))
document.getElementById('finalGrade').value = weightedTotal / totalWeight;
});
<form>
Science: <input type="number" class="science">
<input type="number" class="science">
<input type="number" class="science">
<output id="scienceAverage"></output>
<br> Physics: <input type="number" class="physics">
<input type="number" class="physics">
<input type="number" class="physics">
<output id="physicsAverage"></output>
<br> History: <input type="number" class="history">
<input type="number" class="history">
<input type="number" class="history">
<output id="historyAverage"></output>
<br>
<input type="button" value="Calculate" id="calcBtn">
<output id="finalGrade"></output>
</form>
答案 5 :(得分:4)
var tests = [
document.getElementById('test1').value || false,
document.getElementById('test2').value || false,
document.getElementById('test3').value || false
];
var average = 0,
length = 0;
for (var i = 0; i < tests.length; i++) {
if (tests[i] !== false) {
average += Number( tests[i] );
length ++;
}
}
average = average / length;
这是ES5解决方案。您可以做的短一些,但是我认为这很直观。
答案 6 :(得分:3)
您正在将值除以3
,这就是为什么结果比预期少的原因。
scienceTest1,scienceTest2.....
),而使用循环将值存储在array
Number(scienceTest1) + Number(scienceTest2) + Number(scienceTest3)) / 3
写作是不好的,因为您可以进行更多的测试,并且有更多的类型错误机会。而是将值存储在数组中,最后使用Array.prototype.reduce()
添加它们。value !==''
推入数组之前检查其是否//This is list of subjects. You can change it will work same
let subjects = ['science','physics','history'];
let noOfTests = 3;
//add <form> element to body
document.body.innerHTML = '<form></form>'
//getting that form as an element.
let form = document.querySelector('form')
//Creating the HTML dymamically
subjects.forEach(sub =>{
//setting the title of the subject
form.innerHTML += sub + ':' + '<br>';
for(let i = 0;i<noOfTests;i++){
//generating input feilds equal of 'noOfTests' for each subject
form.innerHTML += `<input type="number" id="${sub}Test${i+1}" /><br>`
}
//adding the output element to after addign all inputs.
form.innerHTML += `<output id="${sub}Average"></output><br>`
})
//Adding calculate button and finalOuput element.
form.innerHTML += `<br><input type="button" value="Calculate" id="calcBtn">
<output id="finalGrade"></output>`
document.getElementById('calcBtn').addEventListener('click', function() {
//'total' is array which will contain average of each subject
let total = [];
//looping thorugh each subject in 'subjects' array.
subjects.forEach(sub => {
//'vals' will store the values currect subject we are looping
let vals = []
for(let i = 0;i<noOfTests;i++){
//getting the value of each input feild of current subject
let val = document.getElementById(`${sub}Test${i+1}`).value;
//check if input have a value so we push it into the vals array.
if(val !== '') vals.push(val);
}
//getting average of all values using reduce
let result = vals.reduce((ac,a) => ac + Number(a),0)/vals.length;
//adding result(average) to the output of current subject.
document.getElementById(`${sub}Average`).innerHTML = result
//adding the average of current subject of the 'total' array.
total.push(result);
})
//At last find the average of total averages and add it to 'finalGrade'
total = total.filter(x => !isNaN(x));
document.getElementById('finalGrade').innerHTML = total.reduce((ac,a) => ac + a,0)/total.length;
});
,以便获得正确的平均值。
代码是完全动态的,您可以具有任何主题以及任何 没有测试
input{
border-radius:5px;
padding:3px;
margin:5px;
font-size:20px;
}
form{
font-size:20px;
font-family:sans-serif;
text-transform:capitalize;
}
bulkCopy.DestinationTableName = "dbo.Student";
bulkCopy.ColumnMappings.Add("<list field name>", "<database field name>");
//Map all your column as above
bulkCopy.WriteToServer(dataTable);
答案 7 :(得分:3)
在该功能中引入计数器。每次单击后,检查输入值是否为”,因为输入值将在转换前为字符串。如果不执行任何操作,则三元操作将返回 false
test1!=''?num++:false;
如果test1==''
,则 false ,否则增加计数器。在计算平均值之前,请检查计数器是否为0,是否将其设置为1。如果为零,则除以零的结果将为无穷大,我们将获得 NaN 作为输出,并将计数器设置为1将得到0。
document.getElementById('calcBtn').addEventListener('click', function() {
let num=0;
var test1 = document.getElementById('test1').value;
test1!=''?num++:false;
var test2 = document.getElementById('test2').value;
test2!=''?num++:false;
var test3 = document.getElementById('test3').value;
test3!=''?num++:false;
var average = document.getElementById('average');
num==0?num++:false;
average.value = (Number(test1) + Number(test2) + Number(test3)) / num;
});
<form>
<input type="number" id="test1">
<input type="number" id="test2">
<input type="number" id="test3">
<output id="average"></output>
<br>
<input type="button" value="Calculate" id="calcBtn">
</form>
答案 8 :(得分:2)
已经有一些解决方案。这是我的。
您的代码中有一些需要优化的地方,我认为基于像这样的简单配置数组动态创建HTML是一个好主意
const subjects = [{
name: 'science',
numberOfTests: 3
}, {
name: 'physics',
numberOfTests: 2
}, {
name: 'history',
numberOfTests: 3
}];
因此,如果主题或测试数量发生变化,则无需更改代码,而只需更改此配置。 我试图注释我的代码示例以使其易于理解,在此做什么。但这不是重要的部分。更重要的是 您需要了解计算部分中发生的事情以确保计算正确。所以我从那部分开始。
如果在测试结果输入中添加 name 属性,并为相同主题的每个输入赋予相同的名称,则可以轻松地检索该输入的NodeList,检查每个Node的值并计算基于它。这样您就知道了学生为每门科目所进行的测试的值和次数。
让我们看看
/* EventListener for the calculate button */
btn.addEventListener('click', function(e) {
e.preventDefault(); // don't submit the form
var totalAvSum = 0; // var for the total of all subject average totals
/* for all subjects in your configuration array */
subjects.forEach(function(subject) {
/* NodeList of all inputs with Name subject.name+'Test' */
let subjResInputs = document.getElementsByName(subject.name+'Test');
let testTotal = 0; // sum of test results
let testCnt = 0; // number of tests the student took
let tval; // value of input
/* for each input of the subject */
Array.prototype.map.call(subjResInputs, function(t){
tval = (t.value * 1); // make sure, value is treated as number
if (tval > 0) { // only if there is a value
testTotal += tval; // add test result
testCnt += 1; // increase test count
}
});
/* calculate average and show it in output */
totalAvSum += (testTotal/testCnt);
document.getElementById(subject.name+'Average').textContent = (testTotal/testCnt);
});
/* after calculating average per subject show total average */
document.getElementById('totalAverage').textContent = totalAvSum/subjects.length;
});
我在这里使用document.getElementsByName()来获取每个主题的输入元素的NodeList。然后,我使用array.map()浏览该列表。要检查输入是否有值,我将值乘以1(给出数字),并且仅在结果大于0时才进行计算。
其余就是HTML的动态内容。
/* This is your configuration.
The form will be created based on that configuration.
So you don't need to change anything in the code if
subjects or number of tests change. */
const subjects = [{
name: 'science',
numberOfTests: 3
}, {
name: 'physics',
numberOfTests: 2
}, {
name: 'history',
numberOfTests: 3
}];
/* this functioncreates the form table */
function createFormTable() {
var tr, td, txt, outp, btn, frmTbl;
// frmTbl = document.getElementById('formTable');
/* create table */
frmTbl = document.createElement('table');
frmTbl.setAttribute('id', 'formTable'); // set id to 'formTable'
/* create table head */
tr = document.createElement('tr');
td = document.createElement('th');
txt = document.createTextNode('subject');
td.appendChild(txt);
tr.appendChild(td);
td = document.createElement('th');
txt = document.createTextNode('test results');
td.appendChild(txt);
tr.appendChild(td);
td = document.createElement('th');
txt = document.createTextNode('arith. mean');
td.appendChild(txt);
tr.appendChild(td);
/* add table head to table */
frmTbl.appendChild(tr);
/* create table row for each subject
the table row object is created in function createSubjectRow
and here added to the table */
subjects.forEach(function(subject) {
frmTbl.appendChild(createSubjectRow(subject)); // add tr to table
});
/* row with total average */
/* create tr element */
tr = document.createElement('tr');
td = document.createElement('th'); // td for text total
td.setAttribute('colspan', 2);
td.style.textAlign = 'right';
txt = document.createTextNode('total'); // textNode
td.appendChild(txt); // add textNode to td
tr.appendChild(td); // add td to tr
frmTbl.appendChild(tr); // add tr to table
td = document.createElement('td'); // td for total average output
outp = document.createElement('output'); // create output element
outp.setAttribute('id', 'totalAverage'); // set id
td.appendChild(outp); // add output to td
tr.appendChild(td); // add td to tr
frmTbl.appendChild(tr); // add tr to table
/* button */
btn = document.createElement('button');
btn.setAttribute('id', 'calcBtn');
txt = document.createTextNode('calculate');
btn.appendChild(txt);
// document.getElementById('gradesForm').appendChild(btn);
/* add button to last row in table */
tr = document.createElement('tr');
td = document.createElement('th'); // td for button
td.setAttribute('colspan', 3);
td.appendChild(btn); // add button to td
tr.appendChild(td); // add td to tr
frmTbl.appendChild(tr); // add tr to table
/* EventListener for the calculate button */
btn.addEventListener('click', function(e) {
e.preventDefault(); // don't submit the form
var totalAvSum = 0; // var for the total of all subject average totals
/* for all subjects in your configuration array */
subjects.forEach(function(subject) {
/* NodeList of all inputs with Name subject.name+'Test' */
let subjResInputs = document.getElementsByName(subject.name+'Test');
let testTotal = 0;
let testCnt = 0;
let tval;
/* for each input of the subject */
Array.prototype.map.call(subjResInputs, function(t){
tval = (t.value * 1); // make sure, value is treated as number
if (tval > 0) { // only if there is a value
testTotal += tval; // add test result
testCnt += 1; // increase test count
}
});
/* calculate average and show it in output */
totalAvSum += (testTotal/testCnt);
document.getElementById(subject.name+'Average').textContent = (testTotal/testCnt);
});
/* after calculating average per subject
show total average */
document.getElementById('totalAverage').textContent = totalAvSum/subjects.length;
});
return frmTbl;
}
function createSubjectRow(s) {
var tr, td, txt, inp, outp;
/* create tr element */
tr = document.createElement('tr');
/* create td elements for subject s */
td = document.createElement('td'); // td for subject name
txt = document.createTextNode(s.name); // textNode
td.appendChild(txt); // add textNode to td
tr.appendChild(td); // add td to tr
td = document.createElement('td'); // td for subject test results
for (var i = 0; i < s.numberOfTests; i += 1) {
inp = document.createElement('input'); // create input
inp.setAttribute('type', 'number'); // set input type
// inp.setAttribute('id', s.name + 'Test' + i); // set id
/* set name attribute of input to subject name + 'Test'
all test result inputs for the same subject will have the same name */
inp.setAttribute('name', s.name + 'Test');
inp.setAttribute('step', 0.1); // in case, you give grades like 3.5
inp.setAttribute('min', 1);
inp.setAttribute('max', 100);
td.appendChild(inp); // add input to td
}
tr.appendChild(td); // add td to tr
td = document.createElement('td'); // td for average output
outp = document.createElement('output'); // create output element
outp.setAttribute('id', s.name + 'Average'); // set id
td.appendChild(outp); // add output to td
tr.appendChild(td); // add td to tr
return tr; // return the resulting table row object
}
document.getElementById('gradesForm').appendChild(createFormTable());
#formTable td {
border: solid 1px #000;
padding: 6px;
border-spacing: 3px;
}
#formTable th {
border: none;
font-size:0.9em;
text-align: left;
}
input[type="number"] {
width: 4em;
border: solid 1px #999;
margin: 0 3px;
}
<form id="gradesForm">
</form>
答案 9 :(得分:2)
您可以创建一个名为
tests = {}
的对象,并将测试作为数组保留在其中,以举一个例子为例,我仅针对一个主题编写了一些代码,您可以在下面对其进行修改。
此外,我使用了 classes 而不是 id的来减少代码的复杂性和重复性。
更新:更新了以下代码,以使动态和灵活适应多个主题。
document.getElementById('calcBtn').addEventListener('click', function() {
// create a tests object and have subject specific test inside it
var tests = {
"Science": [],
"Physics": [],
"History": []
};
//looping over all subjects
for (var key in tests) {
// this can be looped as well if you have multiple subjects
var test = document.getElementsByClassName(key);
for (i = 0; i < test.length; i++) {
if (test[i].value != null || test[i].value != "") {
tests[key].push(Number(test[i].value));
}
}
// populate average by using reduce function
document.getElementById(key).value = tests[key].reduce((prev, curr) => prev + curr) / tests[key].length;
}
});
<form>
<fieldset>
<legend>Science</legend>
<input type="number" class="Science">
<input type="number" class="Science">
<input type="number" class="Science">
<output id="Science"></output>
</fieldset>
<fieldset>
<legend>Physics</legend>
<input type="number" class="Physics">
<input type="number" class="Physics">
<input type="number" class="Physics">
<output id="Physics"></output>
</fieldset>
<fieldset>
<legend>History</legend>
<input type="number" class="History">
<input type="number" class="History">
<input type="number" class="History">
<output id="History"></output>
</fieldset>
<br>
<input type="button" value="Calculate" id="calcBtn">
</form>
答案 10 :(得分:2)
使用Array length属性并使此值动态化,可以解决固定数字3的除法问题。
第1步:将所有主题放入数组中,并过滤输入内容是否有值。
步骤2 :按主题获取平均值。
第3步:使用权重计算最终得分。
有两个功能被多次使用。
isTruthy
和average
。
为简化平均功能,我将其分解为sum
和average
document.getElementById('calcBtn').addEventListener('click', function() {
// Helper Functions
function isTruthy (score) {
return !!score
}
function sum (scores) {
var total = 0;
for (var counter=0; counter<scores.length; counter++) {
total += (Number(scores[counter]) || 0);
}
return total
}
function average (scores) {
return (sum(scores) / scores.length) || 0
}
// Step 1
var scienceScores = [
document.getElementById('scienceTest1').value,
document.getElementById('scienceTest2').value,
document.getElementById('scienceTest3').value
].filter(isTruthy)
var physicsScores = [
document.getElementById('physicsTest1').value,
document.getElementById('physicsTest2').value,
document.getElementById('physicsTest3').value
].filter(isTruthy)
var historyScores = [
document.getElementById('historyTest1').value,
document.getElementById('historyTest2').value,
document.getElementById('historyTest3').value
].filter(isTruthy)
var scienceAverage = document.getElementById('scienceAverage');
var physicsAverage = document.getElementById('physicsAverage');
var historyAverage = document.getElementById('historyAverage');
var finalGrade = document.getElementById('finalGrade');
// Step 2
scienceAverage.value = average(scienceScores);
physicsAverage.value = average(physicsScores);
historyAverage.value = average(historyScores);
// Step 3
finalGrade.value = (scienceAverage.value * 5 + physicsAverage.value * 3 + historyAverage.value * 2) / 10;
});
<form>
Science: <input type="number" id="scienceTest1">
<input type="number" id="scienceTest2">
<input type="number" id="scienceTest3">
<output id="scienceAverage"></output>
<br> Physics: <input type="number" id="physicsTest1">
<input type="number" id="physicsTest2">
<input type="number" id="physicsTest3">
<output id="physicsAverage"></output>
<br> History: <input type="number" id="historyTest1">
<input type="number" id="historyTest2">
<input type="number" id="historyTest3">
<output id="historyAverage"></output>
<br>
<input type="button" value="Calculate" id="calcBtn">
<output id="finalGrade"></output>
</form>
答案 11 :(得分:2)
什么是获取更改的输入字段数的简单方法
我们可以为每个input
分配一个自定义data
属性,该属性等于input
的值,然后在对空值进行计数时将其排除。以下通用脚本可用于任意数量的课程:
var form = document.querySelector('form');
function calculateAverage(fieldset) {
var total = 0;
var inputs = fieldset.querySelectorAll('input');
for (var input of inputs) {
total += Number(input.value);
input.dataset.value = input.value;
}
return total / fieldset.querySelectorAll('input:not([data-value=""])').length;
}
function displayAverages() {
var fieldsets = form.querySelectorAll('fieldset');
for (var fieldset of fieldsets) {
var avg = calculateAverage(fieldset);
var output = fieldset.querySelector('output');
if (isNaN(avg)) {
output.value = 'Please enter a grade.';
} else {
output.value = 'Average: ' + avg.toFixed(1);
}
}
}
form.querySelector('button').addEventListener('click', displayAverages);
body {
display: flex;
}
fieldset {
margin: 0 0 16px;
}
input {
width: 4em;
}
output {
display: block;
height: 1em;
margin: 8px 0 0 2px;
}
<form>
<fieldset>
<legend>Physics</legend>
<input type="number">
<input type="number">
<input type="number">
<output></output>
</fieldset>
<fieldset>
<legend>History</legend>
<input type="number">
<input type="number">
<input type="number">
<output></output>
</fieldset>
<button type="button">Calculate</button>
</form>
答案 12 :(得分:1)
document.getElementById('calcBtn').addEventListener('click', function() {
var testcount = [];
var count = 0;
testcount = Array.prototype.slice.call(document.getElementsByClassName('test1'))
for(var i=0;i<testcount.length;i++)
{
if(Number(testcount[i].value) > 0)
{
count=count+1;
}
}
var test1 = document.getElementById('test1').value;
var test2 = document.getElementById('test2').value;
var test3 = document.getElementById('test3').value;
var average = document.getElementById('average');
average.value = (Number(test1) + Number(test2) + Number(test3)) / count;
});
<form>
<input type="number" class="test1" id="test1">
<input type="number" class="test1" id="test2">
<input type="number" class="test1" id="test3">
<output id="average"></output>
<br>
<input type="button" value="Calculate" id="calcBtn">
</form>
在上面的
中,通过在输入标签中添加class属性来实现输出(给同一组控件使用相同的名称)。 第二件事是遍历该类对象以获取非空或非零值的计数。
答案 13 :(得分:1)
我的建议是,避免多个输入字段,以便读取多个输入。就我而言,我使用分号来分隔输入字段内的各个值。这样,我可以输入所需的任意多个值(至少一个值)。因此,我的表单如下所示:
<!-- form.html -->
<form>
Science: <input type="text" id="scienceTest">
<output id="scienceAverage"></output>
<br> Physics: <input type="text" id="physicsTest">
<output id="physicsAverage"></output>
<br> History: <input type="text" id="historyTest">
<output id="historyAverage"></output>
<br>
<input type="button" value="Calculate" id="calcBtn">
<output id="finalGrade"></output>
</form>
<script src="script.js"></script>
我的JavaScript看起来像这样:
// script.js
(function() {
var scienceTest = document.getElementById('scienceTest');
var physicsTest = document.getElementById('physicsTest');
var historyTest = document.getElementById('historyTest');
var scienceAverage = document.getElementById('scienceAverage');
var physicsAverage = document.getElementById('physicsAverage');
var historyAverage = document.getElementById('historyAverage');
var finalGrade = document.getElementById('finalGrade');
function sumArray(sum, item) {
return sum + item;
}
document.getElementById('calcBtn').addEventListener('click', function() {
// fetch the string of the input and split into its separate numbers
var scienceGradeStrings = scienceTest.value.split(";");
var physicsGradeStrings = physicsTest.value.split(";");
var historyGradeStrings = historyTest.value.split(";");
// calculate the averages
scienceAverage.value = scienceGradeStrings
// convert the grades from strings to numbers
.map(Number)
// sum all grades together
.reduce(sumArray, 0)
// calculate the average grade
/ scienceGradeStrings.length;
physicsAverage.value = physicsGradeStrings.map(Number).reduce(sumArray, 0) / physicsGradeStrings.length;
historyAverage.value = historyGradeStrings.map(Number).reduce(sumArray, 0) / historyGradeStrings.length;
finalGrade.value = (scienceAverage.value * 5 + physicsAverage.value * 3 + historyAverage.value * 2) / 10;
});
})();