Функция jQuery после .append
Как вызвать функцию после завершения jQuery .append
?
Вот пример:
$("#root").append(child, function(){
// Action after append is completly done
});
Проблема. Когда сложная структура DOM добавляется, вычисление нового размера корневого элемента в обратном вызове функции добавления неверно. Допущения состоят в том, что DOM еще не полностью загружен, только первый ребенок добавленного сложного DOM.
Ответы
Ответ 1
У вас есть много действительных ответов здесь, но никто из них действительно не говорит вам, почему он работает так, как он.
В JavaScript команды выполняются по одному, синхронно в том порядке, в котором они приходят, если вы явно не говорите им, что они асинхронны, используя тайм-аут или интервал.
Это означает, что ваш метод .append
будет выполнен, и ничто другое (без учета любых возможных таймаутов или интервалов, которые могут существовать) будет выполняться до тех пор, пока этот метод не завершит свое задание.
Подводя итог, нет необходимости в обратном вызове, так как .append
будет выполняться синхронно.
Ответ 2
Ну, у меня точно такая же проблема с пересчетом размера, и после частых головных болей я не согласен с тем, что .append()
ведет себя строго синхронно. Ну хотя бы в Google Chrome. См. Следующий код.
var input = $( '<input />' );
input.append( arbitraryElement );
input.css( 'padding-left' );
Свойство padding-left правильно загружается в Firefox, но в Chrome оно пусто. Как и все другие свойства CSS, я полагаю. После некоторых экспериментов мне пришлось согласиться на то, чтобы обернуть "getter" CSS в setTimeout()
с задержкой 10 мс, которая, как я знаю, является UGLY, черт возьми, но единственной, кто работает в Chrome.
Если бы у кого-то из вас была идея, как лучше решить эту проблему, я был бы очень благодарен.
Ответ 3
Хотя Маркус Эквалл абсолютно прав насчет синхронности append, я также обнаружил, что в нечетных ситуациях иногда DOM не полностью отображается браузером при запуске следующей строки кода.
В этом сценарии теневые решения находятся в правильном направлении - с использованием .ready - однако гораздо сложнее связать вызов с исходным добавлением.
$('#root')
.append(html)
.ready(function () {
// enter code here
});
Ответ 4
У меня есть другой вариант, который может быть полезен для кого-то:
$('<img src="http://example.com/someresource.jpg">').load(function() {
$('#login').submit();
}).appendTo("body");
Ответ 5
Использование MutationObserver
может действовать как обратный вызов для метода jQuery append
:
Я объяснил это в другом вопросе, и на этот раз я приведу только пример для современных браузеров:
// Somewhere in your app:
var observeDOM = (() => {
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
return function(obj, callback){
if( MutationObserver ){
// define a new observer
var obs = new MutationObserver(function(mutations, observer){
if( mutations[0].addedNodes.length || mutations[0].removedNodes.length )
callback(mutations);
});
// have the observer observe foo for changes in children
obs.observe( obj, { childList:true, subtree:true });
return obs;
}
}
})();
//////////////////
// Your code:
// setup the DOM observer (on the appended content parent) before appending anything
observeDOM( document.body, ()=>{
// something was added/removed
}).disconnect(); // don't listen to any more changes
// append something
$('body').append('<p>foo</p>');
Ответ 6
Я столкнулся с той же проблемой и нашел простое решение.
Добавить после вызова функции добавления документ готов.
$("#root").append(child);
$(document).ready(function () {
// Action after append is completly done
});
Ответ 7
Я думаю, что это хорошо ответил, но это немного более специфично для обработки "subChild_with_SIZE" (если это происходит от родителя, но вы можете адаптировать его там, где оно может быть)
$("#root").append(
$('<div />',{
'id': 'child'
})
)
.children()
.last()
.each(function() {
$(this).append(
$('<div />',{
'id': $(this).parent().width()
})
);
});
Ответ 8
Я удивлен всеми ответами здесь...
Попробуйте следующее:
window.setTimeout(function() { /* your stuff */ }, 0);
Обратите внимание на тайм-аут 0. Это не произвольное число... как я понимаю (хотя мое понимание может быть немного шатким), есть две очереди событий javascript - одна для макросов и одна для микро-событий. В "более крупной" окружной зоне хранятся задачи, которые обновляют пользовательский интерфейс (и DOM), в то время как микро-очередь выполняет операции типа быстрой задачи.
Также понимайте, что установка тайм-аута не гарантирует, что код выполняет именно это значение. То, что это делает, по существу ставит функцию в высшую очередь (ту, которая обрабатывает UI/DOM), и не запускает ее до указанного времени.
Это означает, что установка таймаута 0 помещает его в UI/DOM-часть очереди событий javascript, которая будет выполняться со следующей возможной вероятностью.
Это означает, что DOM обновляется со всеми предыдущими элементами очереди (например, вставлен через $.append(...);
, а когда ваш код работает, DOM полностью доступен.
(p.s. - Я узнал об этом из "Секретов JavaScript-ниндзя" - отличной книги: https://www.manning.com/books/secrets-of-the-javascript-ninja)
Ответ 9
$.when($('#root').append(child)).then(anotherMethod());
Ответ 10
функция Jquery append возвращает объект jQuery, поэтому вы можете просто пометить метод в конце
$("#root").append(child).anotherJqueryMethod();
Ответ 11
Для изображений и других источников вы можете использовать это:
$(el).one('load', function(){
// completed
}).each(function() {
if (this.complete)
$(this).load();
});
Ответ 12
Самый чистый способ - сделать это шаг за шагом. Используйте каждую функцию, чтобы пройти через каждый элемент. Как только этот элемент будет добавлен, передайте его следующей функции для обработки этого элемента.
function processAppended(el){
//process appended element
}
var remove = '<a href="#">remove</a>' ;
$('li').each(function(){
$(this).append(remove);
processAppended(this);
});
Ответ 13
Я знаю, что это не лучшее решение, но лучшая практика:
$("#root").append(child);
setTimeout(function(){
// Action after append
},100);
Ответ 14
Я столкнулся с этой проблемой при кодировании HTML5 для мобильных устройств. Некоторые комбинации браузера/устройства вызвали ошибки, потому что метод .append() не сразу отражал изменения в DOM (что привело к сбою JS).
По быстрому и грязному решению для этой ситуации было:
var appint = setInterval(function(){
if ( $('#foobar').length > 0 ) {
//now you can be sure append is ready
//$('#foobar').remove(); if elem is just for checking
//clearInterval(appint)
}
}, 100);
$(body).append('<div>...</div><div id="foobar"></div>');
Ответ 15
Да, вы можете добавить функцию callback для любой вставки DOM:
$myDiv.append( function(index_myDiv, HTML_myDiv){
//....
return child
})
Проверьте документацию по JQuery: http://api.jquery.com/append/
И здесь практический, похожий пример:
http://www.w3schools.com/jquery/tryit.asp?filename=tryjquery_html_prepend_func
Ответ 16
Недавно я столкнулся с подобной проблемой. Решение для меня состояло в том, чтобы воссоздать коллекцию. Позвольте мне попытаться продемонстрировать:
var $element = $(selector);
$element.append(content);
// This Doesn't work, because $element still contains old structure:
$element.fooBar();
// This should work: the collection is re-created with the new content:
$(selector).fooBar();
Надеюсь, это поможет!
Ответ 17
В jquery вы можете использовать сразу после добавления
$(function(){
//code that needs to be executed when DOM is ready, after manipulation
});
$() вызывает функцию, которая либо регистрирует обратный вызов, готовый к DOM (если ему передана функция), либо возвращает элементы из DOM (если ей передана строка селектора или элемент)
Вы можете найти больше здесь
разница между $ и $() в jQuery
http://api.jquery.com/ready/
Ответ 18
$('#root').append(child);
// do your work here
Append не имеет обратных вызовов, и это код, который выполняется синхронно - нет риска, чтобы он НЕ выполнялся
Ответ 19
$('#root').append(child).anotherMethod();