Как DOM изменил содержимое страницы только после использования DOMContentLoaded - PullRequest
0 голосов
/ 10 марта 2020

Я работаю над системой cargocollective и пытаюсь изменить существующие метки проекта, используя javascript. Прямо сейчас, когда пользователи вводят адрес, есть 1 или 2 секунды, когда метки переходят с одного этапа на другой, поэтому пользователь сначала видит:

project label - 1'st stage

а затем через несколько секунд см .:

project label - 2'nd stage

Есть ли способ изменить его, чтобы пользователи не увидели изменения после завершения загрузки страницы? это мой текущий код:

<script>
document.addEventListener('DOMContentLoaded', (event) => {
  window.setTimeout(() => {
      let titles = document.querySelectorAll(".thumbnails .title span");
    let titlesArray = Array.from(titles);
    let tArray = [titlesArray.length];
    titlesArray.forEach(el => {
      let titleSplit =[];
      titleSplit = el.textContent.split('---');
      for (let i = 0; i < tArray.length; i++)
      {
        el.textContent = "";
        for (let j = 0; j < titleSplit.length; j++)
        {
          el.innerHTML += `${titleSplit[j]}</br>`;
        }
      }
});
  }, 400);
});
</script>

Несколько вещей, которые я должен упомянуть:
1. Система допускает только внутренние js сценарии, она не позволяет HTML редактирование, что означает только код, который вставляется между тегами скрипта
2. Решение должно быть в javascript для использования в будущем.
3. "---" предназначено только для применения косметики c и заменит SVG-изображение.
4. Расположение тегов скрипта находится в середине файла. кроме того, между сценарием и концом страницы много контента. 5. для view-source: веб-страница в контексте

Ответы [ 2 ]

1 голос
/ 10 марта 2020

Не ждите DOMContentLoaded и не вкладывайте функциональность в setTimeout. Вместо этого поместите <script> сразу после последнего элемента, от которого зависит скрипт - последний .thumbnails .title span:

<div class="thumbnails">
  <div class="title">
    <span>
      ...
    </span>
  </div>
</div>
<script>
// Put the code here
</script>

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

Что касается кода, let tArray = [titlesArray.length]; не имеет особого смысла - вы создаете массив с одним элементом, число, которое вы перебираете во вложенном l oop. Если вы просто хотите заменить --- на пустую строку, а интервалы содержат только простой текст, используйте:

for (const span of document.querySelectorAll(".thumbnails .title span")) {
  span.innerHTML = span.innerHTML.split('---').join('<br><br>');
}

<div class="thumbnails">
  <div class="title">
    <span>
      foobar
      ---
      barbaz
    </span>
  </div>
</div>
<script>
for (const span of document.querySelectorAll(".thumbnails .title span")) {
  span.innerHTML = span.innerHTML.split('---').join('<br><br>');
}
</script>

(вам нужно два <br> с, чтобы между двумя словами было два символа новой строки, чтобы в отображаемом выводе появилась одна пустая строка)


Если вы не можете изменить положение тега <script>, и есть много контента между сценарием и концом HTML, и сценарий запускается до того, как необходимые элементы существуют, тогда вы не сможете сразу же выбрать элементы при запуске сценария и не сможете дождаться, пока DOMContentLoaded не создаст их, поскольку это может занять заметное время между требуемые элементы появляются и когда DOM полностью проанализирован. Единственная альтернатива - присоединить MutationObserver к документу, который может запускать обратный вызов всякий раз, когда вставляется новый узел. Если новый узел является одним из тех, которые вы хотите изменить, измените его. Это гарантирует, что изменение произойдет как можно скорее, перед рендерингом:

<script>
new MutationObserver((mutations) => {
  for (const mutation of mutations) {
    for (const node of mutation.addedNodes) {
      if (node.nodeType === 1 && node.matches('.thumbnails .title span')) {
        node.innerHTML = node.innerHTML.split('---').join('<br><br>');
      }
    }
  }
})
  .observe(document.body, { childList: true, subtree: true });
</script>
<div class="thumbnails">
  <div class="title">
    <span>
      foobar
      ---
      barbaz
    </span>
  </div>
  <div class="title">
    <span>
      foobar
      ---
      barbaz
    </span>
  </div>
</div>

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

0 голосов
/ 27 апреля 2020

Мне удалось исправить мою проблему и решить опубликовать ее здесь для тех, кому это может понадобиться: Некоторые уточнения до:

  1. Как я уже упоминал ранее CargoCollective позволяет добавлять внутренние js сценарии только с помощью опции HTML редактирования (код должен быть вставлен между тегами сценария).
  2. Заполнитель "---" (в моем исходном вопросе) был удален, так как дизайнер попросил меня об этом, поэтому решение не включает его.
  3. Указанная c вспомогательная функция 'thumbnails_render_complete' не была упомянуть в документации CargoCollective, я получил его от их поддержки во время сеанса чата.

Надеюсь, это кому-нибудь поможет

<script>
  Cargo.Event.on('thumbnails_render_complete', function(pid) {
    let titles = document.querySelectorAll(".thumbnails .title span");
    let titlesArray = Array.from(titles);
    let tArray = titlesArray.length;
    titlesArray.forEach(el => {
      let titleSplit =[];
      titleSplit = el.textContent.split('-');
      for (let i = 0; i < tArray; i++) {
        el.textContent = "";
        for (let j = 0; j < titleSplit.length; j++) {
          if ( j === 0 ) {
            el.innerHTML += `${titleSplit[j]}</br>`;
          }
          else {
            let subtext = titleSplit[j];
            el.innerHTML += `${subtext}</br>`;
          }
        }
      }
    });
  });
</script>
...