使用JavaScript强制重新绘制DOM以响应需求

11

这个问题的标题表达了我认为是我特定情况背后的根本问题。

我的情况: 在一个点击处理程序内,我想在一个繁忙的函数开始之前将图像可见(一个“加载”动画)。然后,我希望在函数完成后再次将其设置为不可见。 但实际上,图片从未变成可见状态。我猜测这是因为浏览器在可以进行任何重绘之前等待处理程序结束(我确信有很好的性能原因)。

代码(也可以在此fiddle中查看: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');
    });
});

我在sleepStupidly函数后面添加了alert调用,以显示在休息时浏览器确实重新绘制,但在此之前不会重新绘制。我天真地期望它在将'display'设置为'block'后立即重新绘制;

顺便说一下,在此代码中,我还尝试过附加html标签或交换css类,而不是图像的显示和隐藏。结果相同。

经过所有研究,我认为我需要的是 强制浏览器重新绘制的能力 ,并在此之前停止其他所有事情。

这可能吗?是否可以以跨浏览器的方式实现?也许有我找不到的某个插件……?

我认为可能类似于“jquery css回调”(如此问题中所述:在JQuery中,设置新的css规则后是否可以获取回调函数?)会起作用......但那不存在。

我还尝试将显示、函数调用和隐藏分别放在同一事件的不同处理程序中......但没有用。还添加了setTimeout来延迟函数的执行(如此处推荐:在JavaScript中强制DOM刷新)。

谢谢,希望它也能帮助其他人。

javier

编辑(设置我首选的答案后):

只是进一步解释为什么我选择了window.setTimeout策略。 在我的实际用例中,我已经意识到,为了给浏览器足够的时间重新绘制页面,我必须给它大约1000毫秒(比fiddle示例的50多得多)。我认为这是由于更深层次的DOM树造成的(实际上,不必要地深入)。 setTimeout方法可以让你做到这一点。


1
window.setTimeout() 没有帮助吗? - Marat Tanalin
不需要使用更长的超时延迟。你可能只需要预加载图像,以便能够立即显示它。 - Marat Tanalin
我明白了。但是我理解如果浏览器没有从一开始加载图像(因为它是 display:none,我猜这是合理的),那么情况就会是这样。至少在 Chrome 中不是这种情况,因为它从一开始就加载了图像(可以通过开发者工具看到)。我仍然认为这是由于我正在使用的旧标记(有很多嵌套表格,真的...与我无关!)。实际上,Firefox 做得更好(需要“更少的时间”)...这有意义吗?再次感谢。问候 - javigzz
5个回答

8

使用JQuery showhide回调函数(或其他方式,如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();
        });
    });
});

谢谢你的回答,它也适用于我提出的情况。这就是为什么我也给你点了赞(希望这不违反规则!)。我选择了Marat的答案,因为它更适合我的“真实情况”,它有点更加复杂。因此我认为它更一般化。问候 - javigzz

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


4
为了强制重新绘制,您可以使用offsetHeight或getComputedStyle()。
var foo = window.getComputedStyle(el, null);

或者

var bar = el.offsetHeight;

"

el

"是一个DOM元素。

0

对我有效的是设置以下内容:

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

之后你可以做任何你想做的事情,最终你想要做的是:

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

0

我不确定这个方法是否适用于你的情况(因为我没有测试过),但是在使用JavaScript/jQuery操作CSS时,有时需要强制重新绘制特定元素以使更改生效。

这可以通过简单地请求CSS属性来完成。

在你的情况下,我建议在使用setTimeout之前,在函数调用之前放置一个kitty.position().left;


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接