2013-04-08 5 views
23

Мне нужно точно измерить размеры текста в моем веб-приложении, чего я достигаю, создав элемент (с соответствующими классами CSS), установив его innerHTML, а затем добавив его в контейнер с использованием appendChild.Как определить, когда визуализировался динамически созданный элемент

После этого есть ожидание, прежде чем элемент будет визуализирован, и его offsetWidth можно прочитать, чтобы узнать, насколько широким является текст.

В настоящее время я использую setTimeout(processText, 100), чтобы дождаться завершения рендера.

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

+1

В случае, если кто-то найдет этот вопрос, хорошие ответы можно найти здесь http://stackoverflow.com/a/5629730/697388 и здесь http://stackoverflow.com/a/850995/697388 –

+0

Возможный дубликат [Как проверить, существует ли элемент в видимой DOM?] (http://stackoverflow.com/questions/5629684/how-to-check-if-element-exists-in-the-visible-dom) – iConnor

+0

Возможный дубликат [Is можно определить, когда элемент был обработан с использованием JavaScript?] (http://stackoverflow.com/questions/3667991/is-is-possible-to-determine-when-an-element-has-been-rendered-using -javascript) – Purefan

ответ

29

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

Использование setTimeout для предоставления браузера некоторых служебных данных для рендеринга является самым простым способом. Использование

setTimeout(function(){}, 0) 

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

+1

стоит отметить, что иногда вам нужно будет пройти через некоторое время. У меня возникла проблема с попыткой получить высоту прокрутки контейнера, а свойство иногда было 0, а иногда и правильно. Добавление 500-миллисекундной задержки для захвата этого свойства устранило проблему. – markthewizard1234

+0

Похоже, вы делаете больше, чем вписывается в одну перекраску, @ markthewizard1234. – mystrdat

5

This blog post By Swizec Teller предлагает использовать requestAnimationFrame и проверяет наличие size элемента.

function try() { 
    if (!$("#element").size()) { 
     window.requestAnimationFrame(try); 
    } else { 
     $("#element").do_some_stuff(); 
    } 
}; 

на практике это только когда-либо повторит один раз. Потому что независимо от того, что, по следующей рамке рендеринга, независимо от того, приходит ли она через 60 секунд или минуту, элемент будет визуализирован.

0

когда вы делаете, например

var clonedForm = $('#empty_form_to_clone').clone(true)[0]; 

var newForm = $(clonedForm).html().replace(/__prefix__/g, next_index_id_form); 

// next_index_id_form is just a integer 

Что я здесь делаю?
Я клонировал уже обработанный элемент и изменил отображаемый html.

Далее я добавляю этот текст в контейнер.

$('#container_id').append(newForm); 

Проблема возникает, когда я хочу, чтобы добавить обработчик событий для кнопки внутри NEWFORM, WELL, просто использовать готового события.

$(clonedForm).ready(function(event){ 
    addEventHandlerToFormButton(); 
}) 

Надеюсь, это поможет вам.

PS: Извините за мой английский.

3

Принятый ответ с 2014 года и теперь устарел. A setTimeout может работать, но он не самый чистый и не обязательно гарантирует, что элемент был добавлен в DOM.

Сегодня MutationObserver - это то, что вы должны использовать для определения того, когда элемент добавлен в DOM. MutationObservers теперь широко поддерживаются во всех современных браузерах (Chrome 26+, Firefox 14+, IE11, Edge, Opera 15+ и т. Д.).

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

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

Для краткости я использую синтаксис jQuery для сборки узла и вставки его в DOM.

var myElement = $("<div>hello world</div>")[0]; 

var observer = new MutationObserver(function(mutations) { 
    if (document.contains(myElement)) { 
     console.log("It's in the DOM!"); 
     observer.disconnect(); 
    } 
}); 

observer.observe(document, {attributes: false, childList: true, characterData: false, subtree:true}); 

$("body").append(myElement); // console.log: It's in the DOM! 

Обработчик события observer будет вызывать всякий раз, когда какой-либо узел добавляется или удаляется из document. Внутри обработчика мы затем выполните проверку contains, чтобы определить, находится ли myElement в document.

Вам не нужно выполнять итерацию по каждому мутационному регистру, хранящемуся в mutations, потому что вы можете выполнить проверку document.contains непосредственно на myElement.

Для повышения производительности замените document на конкретный элемент, который будет содержать myElement в DOM.

+0

Это не работает в случае рендеринга текста. –

+0

Файл @ErikGrosskurth document.contains также работает с 'TextNode'. Вот пример: jsfiddle.net/ef9yub3y Но в соответствии с MDN он может не работать со старым IE. Если у вас возникли проблемы с вашей реализацией, не стесняйтесь публиковать сообщения на SO, и я с удовольствием посмотрю. –

+0

Вещь с текстом - это элемент dom, который визуализируется, а затем текст далее мутирует, который наблюдатель уже ввел в оператор if, поэтому наблюдатель хранит начальный моментальный снимок. Это может быть просто хром. Не уверен –

Смежные вопросы