Javascript: обработка событий с несколькими динамическими элементами


Я ищу лучший способ обработки событий для нескольких элементов на странице, которые могут отображаться динамически. В настоящее время я использую этот код:

var myToolbar = document.createElement('div');
setInterval(function () {
    for (let textField of document.querySelectorAll('textarea[name="text"]:not(.modified)')) {
        textField.classList.add('modified');
        textField.addEventListener('focus', function () {
            textField.insertAdjacentElement('beforebegin', myToolbar);
        });
    }
}, 1000);

Это прекрасно справляется с моей задачей, но наличие интервала, работающего все время, кажется неуклюжим.

2 2

2 ответа:

Вы можете использовать MutationObserver. Пример:

setInterval(() => {
  const allDivs = document.querySelectorAll('div');
  const randomDiv = allDivs[Math.floor(Math.random() * allDivs.length)];
  randomDiv.appendChild(document.createElement('div'));
}, 1000);

const obs = new MutationObserver(track);
obs.observe(document.body.children[0], { childList: true, subtree: true });

function track(mutations) {
  mutations.forEach((mutation) => {
    mutation.addedNodes.forEach(addedNode => {
      if (addedNode.tagName === 'DIV') addedNode.classList.add('found');
    });
  });
}
div {
  border: 1px solid black;
  background-color: white;
  height: 20px;
  width: 20px;
}
.found {
  background-color: yellow;
}
<div>
</div>

Для вашего конкретного случая вы хотите найти новые textarea[name="text"]s, поэтому вместо этого вы должны проверить:

if (addedNode.tagName === 'TEXTAREA' && addedNode.name === 'text') {
  // ...
}

Вы должны знать о компонентах, которые вы визуализируете на веб-странице, и их состоянии в вашем приложении. Если это не так, то ваш шаблон дизайна ошибочен и нуждается в более тщательном обдумывании. То, что вы сейчас делаете, - это путь к катастрофе. Добавление слушателей событий волей-неволей внутри setInterval, даже не очищая их - пахнет утечкой памяти.

Компоненты, которые вы изначально визуализируете на веб-странице, вероятно, должны иметь собственные прослушиватели событий для обработки того, что вы называете появление "динамических" элементов. Эти динамические элементы появляются либо из-за того, что ваше приложение помещает их туда, либо пользователь делает что-то, чтобы они появились там. Обе эти вещи можно отслеживать и поддерживать в состоянии приложения.

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

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