[英]How to add event listeners automatically?
我正在处理大量输入(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;
};
我可以以某种方式自动化吗?
最好的方法是只将一个监听器分配给它们的共同父级
document.getElementById(commonParentId).oninput = e =>
document.getElementById("label" + e.target.id.substring(1))
.innerHTML = parseInt(e.target.value) + 3
当可以在未知或大量元素上完成相同任务时,恕我直言,事件委托是最佳选择。
什么是事件委托?
简而言之,您让一个共同的祖先处理您原本分配给单个元素的任务。 例如,不是将单击侦听器绑定到n 个元素,而是将其分配给一个共同的祖先。 ( 阅读更多。)
为什么更好?
如果你不小心加入过多的事件监听器最终会降低你的应用程序的感知性能。 它会让您的用户感到迟钝。
以下是 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>
这是一个简单的演示:
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>
您可以轻松地使用数组和循环:
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;
};
}
有很多框架可以自动化这些事情。 使用纯 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>
在这里我使用 vanilla for 循环,因为本机元素列表不是数组并且不支持 forEach。
我建议再次修改 ids 以查找标签,因为稍后调试它可能会很棘手。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.