[英]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.