принудительное перерисовывание DOM с помощью javascript по требованию

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

моем случае: Внутри обработчика щелчков я хочу сделать изображение видимым (анимация "загрузки") прямо перед запуском функции занятости. Затем я хочу сделать его невидимым снова после завершения функции. Вместо того, что я ожидал, я понимаю, что изображение никогда не становится видимым. Я предполагаю, что это связано с браузером, ожидающим завершения обработчика, прежде чем он сможет сделать что-либо перерисовка (я уверен, что для этого есть хорошие причины).

код (также в этой скрипке: http://jsfiddle.net/JLmh4/2/)

HTML-код:

<img id="kitty" src="http://placekitten.com/50/50" style="display:none">
<div><a href="#" id="enlace">click to see the cat</a> </div>

js:

$(document).ready(function(){
    $('#enlace').click(function(){
        var kitty = $('#kitty');
        kitty.css('display','block');

        // see: http://unixpapa.com/js/sleep.html
        function sleepStupidly(usec)
        {
            var endtime= new Date().getTime() + usec;
            while (new Date().getTime() < endtime)
                ;
        }

        // simulates bussy proccess, calling some function...

        sleepStupidly(4000);

        // when this triggers the img style do refresh!
        // but not before
        alert('now you do see it');

        kitty.css('display','none');
    });
});

я добавил alert звонок сразу после sleepStupidly функция, чтобы показать, что в этот момент отдыха браузер перерисовывается, но не раньше. Я невинно ожидал, что он перерисует сразу после установки "display" на "block";

для record, я также попытался добавить теги html или поменять местами классы css вместо изображения, отображаемого и скрываемого в этом коде. Результат тот же.

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

возможно ли это? Возможно ли это в crossbrowser? Некоторые плагин я не смог найти может...?

я подумал, что, может быть, что-то вроде ' jQuery css callback' (как в этом вопросе:в JQuery можно ли получить функцию обратного вызова после установки нового правила css?) будет делать трюк ... но этого не существует.

Я также попытался разделить показ, вызов функции и скрытие в разных обработчиках для одного и того же события ... но ничего. Также добавление setTimeout для задержки выполнения функции (как рекомендуется здесь:принудительное обновление DOM в JavaScript).

спасибо и я надеюсь, что это также помогать другим.

Хавьера

EDIT (после установки моего предпочтительного ответа):

просто чтобы объяснить, почему я выбрал окно.стратегии через setTimeout. В моем реальном случае использования я понял, что для того, чтобы дать браузеру достаточно времени, чтобы перерисовать страницу, Я должен был дать ей около 1000 миллисекунд (гораздо больше, чем 50 для примера скрипки). Я считаю, что это связано с более глубоким деревом DOM (на самом деле, излишне глубоким). В функции setTimeout давайте подхода позволяет тебе это делать.

5 ответов


использовать window.setTimeout() С некоторой короткой незаметной задержкой для запуска медленной функции:

$(document).ready(function() {
    $('#enlace').click(function() {
        showImage();

        window.setTimeout(function() {
            sleepStupidly(4000);
            alert('now you do see it');
            hideImage();
        }, 50);
    });
});

Live demo


Использовать JQuery show и hide обратные вызовы (или другой способ отображения чего-то вроде fadeIn/fadeOut).

http://jsfiddle.net/JLmh4/3/

$(document).ready(function () {
    $('#enlace').click(function () {
        var kitty = $('#kitty');


        // see: http://unixpapa.com/js/sleep.html
        function sleepStupidly(usec) {
            var endtime = new Date().getTime() + usec;
            while (new Date().getTime() < endtime);
        }

        kitty.show(function () {

            // simulates bussy proccess, calling some function...
            sleepStupidly(4000);

            // when this triggers the img style do refresh!
            // but not before
            alert('now you do see it');

            kitty.hide();
        });
    });
});

чтобы принудительно перерисовать, вы можете использовать offsetHeight или getComputedStyle().

var foo = window.getComputedStyle(el, null);

или

var bar = el.offsetHeight;

" el " является элементом DOM


Я не знаю, работает ли это в вашем случае (поскольку я его не тестировал), но при манипулировании CSS с JavaScript/jQuery иногда необходимо принудительно перерисовывать определенный элемент, чтобы изменения вступили в силу.

это делается путем простого запроса свойства CSS.

в вашем случае, я бы попробовал поставить kitty.position().left; перед вызовом функции до возни с setTimeout.


то, что сработало для меня, устанавливает следующее:

$(element).css('display','none'); 

после этого вы можете делать все, что захочешь, и в конечном итоге вы хотите сделать:

$(element).css('display','block');