Загрузка DOM и добавление простого HTML

Обычно я использую domReady() функции (либо jQuery, либо созданные вручную), когда хочу выполнить какой-то код после того, как я уверен, что DOM страницы полностью загружен (99% случаев - это код инициализации).

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

div.innerHTML += htmlTemplate; // Template which has the "someInput" input
var someInput = document.getElementById('someInput');

Дело в том, можно ли предположить, что input был загружен в DOM? После того, как я добавлю HTML в DIV, нужно ли отправлять код, основанный на новых элементах DOM, в качестве обратного вызова функции domReady?

div.innerHTML += htmlTemplate;
domReady(function(){
    var someInput = document.getElementById('someInput');
    // ...
});

С технической точки зрения... Каждый раз, когда к элементам добавляется простой HTML, DOM переходит в состояние загрузки< /а>?

-- РЕДАКТИРОВАТЬ

Вот функция domReady(), которую я использую:

function domReady(f) {
    /in/.test(document.readyState) ? setTimeout('domReady('+f+')', 9) : f();
}

PS: мне нужна была простая/короткая/независимая от API функция, поэтому я наткнулся на нее некоторое время назад в SE.

Заранее спасибо.


person everton    schedule 04.12.2013    source источник
comment
Событие DOM «загрузка» запускается только один раз, когда оно загружается в первый раз. Дополнительная информация: w3.org/TR/DOM- Уровень-3-События/#event-type-load   -  person Qambar Raza    schedule 04.12.2013
comment
На самом деле, моя текущая функция domReady() полагается на состояние готовности документа... Я добавлю это к вопросу.   -  person everton    schedule 04.12.2013
comment
См. руководство MDN для разработчиков событий.   -  person Givi    schedule 04.12.2013
comment
Я не понимаю... Нужно ли добавлять готовый обработчик событий в DIV, в который я добавляю HTML?   -  person everton    schedule 05.12.2013
comment
Добавление такого HTML-кода (innerHTML += more_stuff;) заставляет браузер повторно анализировать все содержимое затронутого контейнера. Это не самая эффективная вещь.   -  person Pointy    schedule 06.12.2013
comment
Поскольку этот контейнер в то время пуст, я думаю, это не должно быть проблемой.   -  person everton    schedule 07.12.2013


Ответы (3)


Каждый раз, когда к элементам добавляется простой HTML, переходит ли DOM в состояние загрузки?

Нет, это не так. Вы можете рассчитывать на то, что элементы появятся сразу после завершения вызова innerHTML=. Посмотрите этот jsbin, где я трачу 1 секунду, добавляя <li> элементов, используя innerHTML, и каждый раз проверяю, что предыдущие элементы там используют .querySelectorAll.

Настройка element.innerHTML является синхронной: браузер останавливает все, что он делает, чтобы соответствующим образом обновить DOM (что не означает, что страница визуально обновляется, как видно из примера, на который я ссылаюсь), и управление не возвращается к вашему код, пока это не будет сделано.


Пример манипуляций в отдельном DOM-узле:

var tempDiv = document.createElement("div");
tempDiv.innerHTML = getTemplateSomehow();

// Manipulate a button inside the template,
// even though it is not in the DOM yet
var button = tempDiv.querySelector("button");
button.style.color = "red";
button.addEventListener("click", function() {
  alert("button clicked");
});

// Append all children from the parsed template into the DOM
var child;
var target = document.body;

// Keep moving tempDiv's children to the target until it is empty
while(child = tempDiv.firstChild) {
  target.appendChild(child);
}

Рабочий пример: http://jsbin.com/isuLeMi/1/edit.

person Renato Zannon    schedule 06.12.2013
comment
Спасибо! Где я могу найти подтверждение (документы), что добавление element.innerHTML является синхронным с точки зрения загрузки DOM? - person everton; 06.12.2013
comment
Я пытался найти это утверждение явно, но не смог найти никакой документации. Однако я думаю, что это подразумевается в API, поскольку нет никаких событий или обратных вызовов, которые можно было бы привязать к модификации. - person Renato Zannon; 06.12.2013
comment
Я беспокоюсь, потому что шаблон, который я добавляю, может быть большим, и могут происходить странные вещи, если я полагаюсь на незагруженные элементы. У вас есть идея, как это проверить? - person everton; 06.12.2013
comment
Возможно, вы могли бы попробовать тест, похожий на мой, но с более крупными шаблонами... В качестве альтернативы вы можете выполнить свои манипуляции на отдельном узле DOM, чтобы помочь браузеру сделать это с большей производительностью. Можете ли вы добавить примеры того, какое преобразование вам нужно сделать после этого к вашему вопросу? - person Renato Zannon; 06.12.2013
comment
До сих пор сообщения об ошибках полей, маски проверки, прикрепление событий кнопок и т. д. - person everton; 06.12.2013
comment
И вы не используете jQuery? Кажется смелым :) Добавил небольшой пример, пожалуйста, взгляните - person Renato Zannon; 06.12.2013
comment
Я работаю над подключаемым виджетом, думаю, теперь вы понимаете сценарий (а также почему я не могу использовать jQuery и мне нужна простая функция domReady()). Ну, я должен добавить весь шаблон в заранее определенный DIV, так как я могу работать с этим отдельным DIV и добавлять все его содержимое только в DIV страницы? - person everton; 06.12.2013
comment
Вам просто нужно изменить document.body в предпоследней строке на ваш div - person Renato Zannon; 06.12.2013
comment
О, теперь я понял механику tempDiv.firstChild, извините. Я проверю это. - person everton; 06.12.2013
comment
Спасибо за ваше время! - person everton; 09.12.2013

Если вы говорите о событии onload в domReady, то это событие запускается только один раз в жизненном цикле страницы, когда документ полностью загружен браузерами, чтобы наблюдать за определенными элементами, вам нужно будет добавить слушателей «изменения» к этим элементам.

person Pereira    schedule 04.12.2013
comment
Событие изменения запускается для элементов ‹input›, ‹select› и ‹textarea›, когда пользователь фиксирует изменение значения элемента. В отличие от события ввода, событие изменения не обязательно запускается при каждом изменении значения элемента. изменить MDN - person Givi; 04.12.2013
comment
Извините, но я не понимаю, как это применимо к этой ситуации. - person everton; 05.12.2013

Дело в том, что браузер перестает выполнять что-либо при запуске javascript. Это означает, что когда вы добавляете div с идентификатором «Пример», вы не можете получить к нему доступ в том же событии, в котором вы его добавили.
Однако для этого есть (на мой взгляд) чистый обходной путь:

Выполнить часть кода, которая обращается к динамически созданному содержимому через
window.setTimout(func, 0);

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

person RononDex    schedule 06.12.2013