如何自动添加事件监听器?

时间:2020-01-07 17:17:24

标签: javascript dom-events

我正在处理大量输入(100-1000)。我需要为每个人创建一个函数,如下所示:

const range1 = document.getElementById("a1");
const range2 = document.getElementById("a2");

//label1 shows a value from range1 + 3
range1.oninput = function() {
    document.getElementById("label1").innerHTML = parseInt(this.value) + 3;
};
range2.oninput = function() {
    document.getElementById("label2").innerHTML = parseInt(this.value) + 3;
};

我可以通过某种方式使它自动化吗?

5 个答案:

答案 0 :(得分:1)

最好的方法是仅将一个侦听器分配给其共同的父母

document.getElementById(commonParentId).oninput = e =>
  document.getElementById("label" + e.target.id.substring(1))
    .innerHTML = parseInt(e.target.value) + 3

答案 1 :(得分:1)

当可以在未知或大量元素上完成相同任务时,事件委托是最好的选择,恕我直言。

什么是事件委托?

简而言之,您可以让一个共同的祖先处理原本分配给各个元素的任务。例如您无需将点击侦听器绑定到 n 元素,而是将其分配给一个共同的祖先。 (Read more。)

为什么更好?

如果您不小心添加过多的事件侦听器,则 最终会降低应用的感知性能。您的用户会觉得呆滞。

这是约翰·雷西格(John Resig)所说的:

事件委托是一种监视大量元素事件的有效方法。

来源:https://johnresig.com/apps/workshop/adv-talk/index2.html#3

演示时间!

每2秒钟,我会将以下元素添加到DOM中:(生成X)

<div>
  <input type="range" id="inpX"/>
  <label for="inpX"><!-- SOME DYNAMIC VALUE --></label>
</div>

用户调整范围后,<label>将立即更新。

全部带有一个事件监听器!

// set el content to given txt
const write = (el, txt) => el.innerText = txt;

// return the <label> for given id
const label = id => document.querySelector(`label[for="${id}"]`);

// one global event listener - event delegation FTW!
document.body.addEventListener('input', ev => {
  const {id, value} = ev.target;
  write(label(id), parseInt(value) + 3); 
});
<script>
// This code is only for the demo
// It is not part of the answer

function append(n) {
  const div = document.createElement('div');
  const id = `inp${n}`;
  div.innerHTML = `
    <input type="range" id="${id}"/>
    <label for="${id}"></label>
  `;
  document.body.appendChild(div);
}

function start() {
  let n = Date.now();
  append(n++);
  start.timer = setInterval(() => append(n++), 2000);
}

function stop() {
  clearInterval(start.timer);
}
</script>

<button onclick="start()">START</button>
<button onclick="stop()">STOP</button>

<hr>

答案 2 :(得分:0)

这是一个简单的演示:

const ranges = document.querySelectorAll("input[type=range]");
for (i = 0; i < ranges.length; ++i) { //for each input[type=range]
  ranges[i].oninput = oninput; //set on change
  oninput.call(ranges[i]); //set on load
}

function oninput() {
  this.parentElement.querySelector("span").innerHTML = parseInt(this.value) + 3;
};
<label><input type=range /><span></span><label><br />
<label><input type=range /><span></span><label>

答案 3 :(得分:0)

您可以轻松地使用数组和循环:

let inputNum = 100;
let range = [];

for(let i = 1; i <= inputNum; i++) {
    range[i] = document.getElementById(`a${i}`);
    range[i].oninput = function() {
        document.getElementById(`label${i}`).innerHTML = parseInt(this.value) + 3;
    };
}

答案 4 :(得分:-1)

有很多框架可以使这些事情自动化。 用普通的html / js可以做什么:

<label for='a1'></label>
<label for='a2'></label>
<input id='a1' class='range-input-output-to-label'/>
<input id='a2' class='range-input-output-to-label'/>
<script>
  const inputs = document.getElementsByClassName('number-input-output-to-label')

  const outputNumberToLabel = (e) => {
    const labels = e.target.labels
    for (let i = 0; i < labels.length; i++)
      labels[i].innerText = parseInt(e.target.value) || 0
  }

  for (let i = 0; i < inputs.length; i++)
    inputs[i].oninput = outputNumberToLabel
</script>

在这里,我将香草用于循环,因为本机元素列表不是数组,并且不支持forEach。

我建议再次修改ID以查找标签,因为稍后进行调试可能很棘手。