从多个输入计数的JS函数

JS function that counts from multiple inputs

我制作了一个简单的计算器,它获取用户在 中输入的信息,然后使用两个常量执行操作并在选定的 中给出结果。

我总共有 5 个输入和 5 个输出。对于每个输入和输出,我有 2 个 const.

代码看起来像这样:

const suprqMean = 3.93;
const usabilityMean = 4.06;

const suprqSD = 0.29;
const usabilitySD = 0.29; 

{
  const input = document.querySelector("#formGroupExampleInput");
  const log = document.getElementById("#suprq");

  input.addEventListener("change", updateValue);

  function updateValue(e) {
    suprq.textContent = (e.target.value - suprqMean) / suprqSD;
  }
}

{
  const input = document.querySelector("#formGroupExampleInput1");
  const log = document.getElementById("#usability");

  input.addEventListener("change", updateValue);

  function updateValue(e) {
    usability.textContent = (e.target.value - usabilityMean) / usabilitySD;
  }
}
<form class="leftForm container">
  <div class="form-group">
    <label for="formGroupExampleInput">SUPR-Q raw</label>
    <input type="number" class="form-control" id="formGroupExampleInput" placeholder="SUPR-Q raw">
  </div>
  <div class="form-group">
    <label for="formGroupExampleInput2">Usability raw</label>
    <input type="number" class="form-control" id="formGroupExampleInput1" placeholder="Usability raw">
  </div>
</form>

<table class="table table-striped table-dark">
  <thead>
    <tr>

      <th scope="col">Z-Score</th>
      <th scope="col">Result</th>

    </tr>
  </thead>
  <tbody>
    <tr>

      <td>SUPR-Q:</td>
      <td id="suprq"></td>

    </tr>
    <tr>

      <td>Usability:</td>
      <td id="usability"></td>

    </tr>
  </tbody>
</table>

它可以工作,但 JS 代码看起来很糟糕。有什么办法可以优化JS代码吗?我希望现在可以实时输入结果。

您可以通过检查 e.target.id 将两个函数合二为一,并且 select 同时输入两个值以循环并添加事件侦听器:

const suprqMean = 3.93;
const usabilityMean = 4.06;
const suprqSD = 0.29;
const usabilitySD = 0.29;

document.querySelectorAll("[id^=formGroupExampleInput").forEach(el => {
  el.addEventListener("change", updateValue);
});

function updateValue(e) {
  inpVer = e.target.id === "formGroupExampleInput" ? true : false;
  outEl = inpVer ? suprq : usability;
  outVal = inpVer ? (e.target.value - suprqMean) / suprqSD : (e.target.value - usabilityMean) / usabilitySD;
  outEl.textContent = outVal;
}
<form class="leftForm container">
  <div class="form-group">
    <label for="formGroupExampleInput">SUPR-Q raw</label>
    <input type="number" class="form-control" id="formGroupExampleInput" placeholder="SUPR-Q raw">
  </div>
  <div class="form-group">
    <label for="formGroupExampleInput2">Usability raw</label>
    <input type="number" class="form-control" id="formGroupExampleInput1" placeholder="Usability raw">
  </div>
</form>

<table class="table table-striped table-dark">
  <thead>
    <tr>

      <th scope="col">Z-Score</th>
      <th scope="col">Result</th>

    </tr>
  </thead>
  <tbody>
    <tr>

      <td>SUPR-Q:</td>
      <td id="suprq"></td>

    </tr>
    <tr>

      <td>Usability:</td>
      <td id="usability"></td>

    </tr>
  </tbody>
</table>

看起来您在该 JS 代码中有点重复自己。

通常的补救方法是将重复的代码重构为可重用的函数:

const suprqMean = 3.93;
const usabilityMean = 4.06;

const suprqSD = 0.29;
const usabilitySD = 0.29;


function listenForChanges (inputId, logId, output, mean, SD) {
  const input = document.querySelector(inputId);
  const log = document.querySelector(logId);

  input.addEventListener("change", updateValue);

  function updateValue(e) {
    output.textContent = (e.target.value - mean) / SD;
  }
}

listenForChanges("#formGroupExampleInput", "#suprq", suprq, suprqMean, suprqSD)
listenForChanges("#formGroupExampleInput1", "#usability", usability, usabilityMean, usabilitySD)

不过还有一点感觉很奇怪。在您的原始代码段(以及我的代码段)中,引用了两个从未声明的变量:suprqusability.

但除此之外,您是否喜欢将函数的使用作为使代码不那么“糟糕”的第一步?

如果你有很多这样的,下一步可能是为所有输入对创建一个数据结构,并在每个输入对上循环调用这个函数:

const all = [{
  inputId: "#formGroupExampleInput",
  logId: "#suprq",
  output: suprq,
  mean: 3.93,
  SD: 0.29
}, {
  inputId: "#formGroupExampleInput1",
  logId: "#usability",
  output: usability,
  mean: 4.06,
  SD: 0.29
}]

all.forEach(listenForChanges)

function listenForChanges ({inputId, logId, output, mean, SD}) {
  const input = document.querySelector(inputId);
  const log = document.querySelector(logId);

  input.addEventListener("change", updateValue);

  function updateValue(e) {
    output.textContent = (e.target.value - mean) / SD;
  }
}

请注意,我在这里稍微更改了函数,让它接受单个对象参数而不是一系列参数。这只是为了更容易将所有内容与 forEach.

粘合在一起

这是一个 'condensed' 版本

const values = {
  suprqMean: 3.93,
  usabilityMean: 4.06,
  suprqSD: .29,
  usabilitySD: .29
};
["suprq", "usability"].map((slug => {
  document.querySelector(`#${slug}Input`).addEventListener("change", (clicked => {
    document.getElementById(`${slug}`).textContent = (clicked.target.value - values[`${slug}Mean`]) / values[`${slug}SD`]
  }))
}));
<form class="leftForm container">
  <div class="form-group">
    <label for="formGroupExampleInput">SUPR-Q raw</label>
    <input type="number" class="form-control" id="suprqInput" placeholder="SUPR-Q raw">
  </div>
  <div class="form-group">
    <label for="formGroupExampleInput2">Usability raw</label>
    <input type="number" class="form-control" id="usabilityInput" placeholder="Usability raw">
  </div>
</form>

<table class="table table-striped table-dark">
  <thead>
    <tr>

      <th scope="col">Z-Score</th>
      <th scope="col">Result</th>

    </tr>
  </thead>
  <tbody>
    <tr>

      <td>SUPR-Q:</td>
      <td id="suprq"></td>

    </tr>
    <tr>

      <td>Usability:</td>
      <td id="usability"></td>

    </tr>
  </tbody>
</table>

其他人展示了使用配置数组生成处理程序的方法。

您还可以从相同的配置生成 HTML,这意味着添加一个新类型只是多一个配置条目的问题:

const config = [
  {title: 'SUPR-Q', mean: 3.93, sd: 0.29, input: 'formGroupExampleInput', log: 'suprq'},
  {title: 'Usability', mean: 4.06, sd: 0.29, input: 'formGroupExampleInput1', log: 'usability'}
]

document.getElementById('main').innerHTML = `
<form class="leftForm container">
  ${config .map (({title, input}) => `  <div class="form-group">
    <label for="${input}">${title} raw</label>
    <input type="number" class="form-control" id="${input}" placeholder="${title} raw">
  </div>`) .join ('\n'  )}
</form>

<table class="table table-striped table-dark">
  <thead><tr><th scope="col">Z-Score</th><th scope="col">Result</th></tr></thead>
  <tbody>${config .map (({title, output}) => 
      `<tr><td>${title}</td><td id="${output}"></td></tr>`).join('\n    ')
  }</tbody>
</table>`

config .forEach (({title, mean, sd, input, log}) => {
  const inputElt = document.getElementById(input);
  const logElt = document.getElementById(log);

  inputElt.addEventListener("change", function (e) {
    logElt.textContent = (e.target.value - mean) / sd;
  })
})
<div id="main"></div>

我也换成了一致的getElementById。我们可以在这里轻松地使用 querySelector,但是当我们总是得到 id 时,混合使用它们感觉很奇怪。