Заставить браузер немедленно перерисовывать элемент dom

Мне нужно вставить огромную html-разметку в какой-то элемент dom, что займет некоторое время. Это причина, по которой я хочу отобразить индикатор предварительного загрузчика. У меня есть два блока: #preloader и #container. Некоторый код сначала отображает предварительный загрузчик, а затем начинает вставлять большую html-разметку.

Проблема в том, что прелоадер не отображается до тех пор, пока браузер не закончит рендеринг html-разметки. Я пробовал много решений (многие из них описаны здесь), но пока безуспешно.

Пример доступен ниже: https://jsfiddle.net/f9f5atzu/

<div id='preloader'>Preloader...</div>
<div id='container'>Container...</div>

#preloader {
  display: none;
  background-color: #f00;
  color: #fff;
  hight: 100px;
  text-align: center;
  padding: 10px 20px;
}

#container {
  background-color: #ccc;
}


setTimeout(function() {
  // Define variables
  let domPreloader = document.getElementById('preloader');
  let domContainer = document.getElementById('container');
  const html = Array(100000).fill("<div>1</div>");

  // Display preloader
  domPreloader.style.display = 'hide';
  domPreloader.offsetHeight;
  domPreloader.style.webkitTransform = 'scale(1)';
  domPreloader.style.display = 'block';

  // Render a big html
  domContainer.innerHTML = html;
}, 1000);

Есть ли решения проблемы?


person Dmitriy    schedule 02.08.2016    source источник


Ответы (1)


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

Вместо того, чтобы инкапсулировать весь этот блок в setTimeout(), вы должны просто изменить часть рендеринга.

Пожалуйста, попробуйте что-нибудь в этом духе:

// Define variables
let domPreloader = document.getElementById('preloader');
let domContainer = document.getElementById('container');

// Display preloader
domPreloader.style.webkitTransform = 'scale(1)';
domPreloader.style.display = 'block';

// Render a big html
setTimeout(render, 100);

function render() {
  const html = Array(100000).fill("<div>1</div>");
  domContainer.innerHTML = html;

  // Hide preloader
  domPreloader.style.display = 'none';
}

JSFiddle

person Arnauld    schedule 02.08.2016
comment
Спасибо за ответ. Я надеялся, что есть какой-то способ контролировать отрисовку во время одного и того же стека выполнения. - person Dmitriy; 02.08.2016
comment
Возможно ли, что браузер не останавливает анимацию в каком-либо блоке (через свойство css backgroud-image или анимацию css) во время рендеринга какого-либо другого блока? - person Dmitriy; 03.08.2016
comment
Если операция рендеринга сильно загружает процессор, любая анимация, вероятно, будет как минимум прерывистой, если не полностью зависшей. Решение состоит в том, чтобы разделить вашу операцию на более мелкие (например, 100 x html = Array(1000).fill("<div>1</div>"); в вашем примере) и использовать setTimeout() для запуска следующего пакета. - person Arnauld; 03.08.2016