Как автоматически добавлять прослушиватели событий? - PullRequest
2 голосов
/ 07 января 2020

Я работаю с большим количеством входов (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 ]

1 голос
/ 08 января 2020

Когда одну и ту же задачу можно выполнить с неизвестным или большим количеством элементов, делегирование событий является лучшим вариантом IMHO.

Что такое делегирование событий?

В двух словах, вы позволяете общему предку справиться с задачей, которую вы в противном случае назначили бы отдельным элементам. например, вместо привязки прослушивателя щелчка к элементам n , вы назначаете его один раз общему предку. ( Подробнее .)

Почему это лучше?

Если вы не будете осторожны, добавив слишком много прослушивателей событий сделает в конечном итоге ухудшает воспринимаемую производительность вашего приложения. Он будет чувствовать себя медлительным sh для ваших пользователей.

Вот что Джон Резиг говорит по этому поводу:

Делегирование событий - эффективный способ следить за событием на большом количестве элементы.

Источник: 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> будет обновлено, как только пользователь установит диапазон.

Все с точно one слушатель событий!

// 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>
1 голос
/ 07 января 2020

Лучший способ - назначить только одного слушателя общему родителю

document.getElementById(commonParentId).oninput = e =>
  document.getElementById("label" + e.target.id.substring(1))
    .innerHTML = parseInt(e.target.value) + 3
0 голосов
/ 07 января 2020

Вы можете легко использовать массивы и циклы:

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;
    };
}
0 голосов
/ 07 января 2020

Вот простая демонстрация:

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>
0 голосов
/ 07 января 2020

Существует множество платформ для автоматизации таких вещей. Что можно сделать с простым 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 для циклов, потому что собственные списки элементов не являются массивами и не поддерживают forEach.

I ' Я предлагаю снова изменить идентификаторы, чтобы найти метку, потому что это может быть сложно отладить позже.

...