Подтвердить что ты не робот

Функция jQuery после .append

Как вызвать функцию после завершения jQuery .append?

Вот пример:

$("#root").append(child, function(){
   // Action after append is completly done
});

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

4b9b3361

Ответ 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>');

Ответ 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();