Как ждать изменений DOM для рендеринга? (MutationObserver не работает) - PullRequest
1 голос
/ 11 января 2020

У меня есть дерево узлов DOM, и я удалил несколько детей. Я хотел бы определить обновленный размер дерева DOM.

MutationObserver не работает, потому что он уведомляет об изменениях модели DOM, но на самом деле рендеринг еще не завершен, поэтому размер еще не обновлен .

Есть хакерские способы сделать это (setTimeout (delay) или несколько вложенных requestAnimationFrame ()), но я не хочу в дальнейшем сталкиваться с неожиданными проблемами с размерами.

Есть ли нехакерский способ сделать это?

1 Ответ

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

Обновление макета коробки, также известного как «reflow», может быть запущено синхронно и не требует «полного рендеринга». Вы можете увидеть этот ответ для более подробной информации о синхронности операций рендеринга.

Так что в вашем случае вы можете напрямую получить новые размеры ваших элементов сразу после того, как вы обновили DOM потому что получение этого размера само по себе вызовет перекомпоновку; нет необходимости использовать MutationObserver.

const elem = document.getElementById('elem');
console.log('initial', elem.offsetHeight);
elem.querySelectorAll('p:not(.notme)').forEach(el=>el.remove());
// getting '.offsetHeight' triggers a reflow
console.log('after removing', elem.offsetHeight);
<div id="elem">
  <p>Hello</p>
  <p>Hello</p>
  <p>Hello</p>
  <p>Hello</p>
  <p>Hello</p>
  <p class="notme">Hello</p> 
</div>

Хотя будьте осторожны, запуск перекомпоновки имеет некоторые затраты с точки зрения производительности, поэтому, если вы боитесь, что другие вещи могут впоследствии изменить DOM, вы можете подождать для итерации события-l oop рисования, используя requestAnimationFrame перед вызовом одного из методов, вызывающих его.

const elem = document.getElementById('elem');
console.log('initial', elem.offsetHeight);
elem.querySelectorAll('p:not(.notme)').forEach(el=>el.remove());

// wait the painting frame in case other operations also modify the DOM
requestAnimationFrame(()=> {
  console.log('after removing', elem.offsetHeight);
});
<div id="elem">
  <p>Hello</p>
  <p>Hello</p>
  <p>Hello</p>
  <p>Hello</p>
  <p>Hello</p>
  <p class="notme">Hello</p> 
</div>

Ps: для тех, кто все еще интересуется Y этой XY-проблемы, вы можете взглянуть на этот Q / A , который демонстрирует использование предстоящего requestPostAnimationFrame и предлагает для него обезьяну-патч.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...