Javascript too fast for DOM-manipulation?

五迷三道 提交于 2020-03-06 03:25:34

问题


In Javascript I load some elements via AJAX from a server, and for each data-element I create a <div> that contains another div and an <img>. The inner div contains between 2 and 5 lines of text. I arrange three of this items side by side in a row, then the next three in the next row and so on.

But since the texts have different lengths, I want to do some fine-adjustment of the elements within each row. I want the top-edges of all three images to be on the same height. To do this, I do this:

  • Insert the three <div><div>text</div><img></div>-blocks into their container.
  • Get the heights of the three <div>text</div>-elements,
  • calculate their maximum, and then
  • set their padding-top properties in a way that gives them all the same height.

In Safari and Chrome this works perfectly fine when I turn on the console and set breakpoints to watch what is going on in detail.

But when I turn off breakpoints in this two browsers, the text-diffs don't get their correct padding-values.

I am pretty sure, that - at breakpoints off - the browser is still working on inserting the three dom-elements and rendering the pictures, when javascript tries to measure the heights of the text-divs. So it measures them at a time when they don't have their final values. The script reads wrong values and so it puts wrong values to the padding-top-property.

This does not happen in all browsers:

When running normally (without console and breakpoints) it works always fine within:

  • Firefox
  • Opera
  • Internet Explorer (running in a virtual Machine on my iMac)

But I have those problems in:

  • Safari
  • Chrome

What can I do to ensure, that the measurement of an elements height happens when the rendering-machin has finished its manipulation?


EDIT:

I found out another very important detail:

The problem occurs, because of the height of the text-div above the image. Sometimes the text fits very tightly into two rows. One small letter more in any of the rows and it would be three rows.

In this case my script, that runs immediately after the div was created, measures a height of three lines (60 pixel), and everything would be absolutely correct, if this div did really contain 3 lines of text. My script manipulates the elements in a manner that would be perfect if this div really was 3 lines high.

But obviously, some milliseconds after my script was running, the browser (Safari and Chrome) performs an improvement of font-rendering. And then suddenly the text fits into 2 lines, which makes the text-div only 40 pixels high. And so the image moves up 20 pixels, and this destroys my just processed result (all images was at the same position)

So,does this give you any idea on how to solve the problem? Is there a way to let that part of my script run after all rendering-polishing has finished? Is there an event like onFinishingRenderingImprovementsDone?

(written on May the 4th be with you = Star Wars day)


回答1:


How about having your script run with a short delay - setTimeout(function() {[your code here]}, 100) (or however long it needs...) - and see if you can simply avoid the problem altogether? Less than a second probably, and for an async action, adding a very short wait would likely not be noticeable.




回答2:


You can monitor the height of the elements, and when an element height changes, you can recalculate the padding.

Example:

$.fn.changeHeight = function(callback){
    return this.each(function(i, e){
        var el = $(e), height = el.height();
        window.setInterval(function(){
            var h = el.height();
            if (h != height) {
                height = h;
                callback.call(e);
            }
        }, 100);
    });
};

function rndText() {
    var txt = '';
    for (var i = Math.floor(Math.random() * 20); i >= 0; i--) {
        txt += 'asdf ';
    }
    return txt;
}

for (var i = 0; i < 10; i++) {
    var d = $('<div>').append(
        $('<div>').prop('contenteditable', true).text(rndText()).changeHeight(resize)
    ).appendTo('body');
}

resize();

function resize() {
    console.log('resize');
    var height = 0;
    $('body > div').each(function(i, e) {
        var d = $(e);
        var h = d.find('div').height();
        if (h > height) height = h;
    });
    $('body > div').each(function(i, e) {
        var d = $(e);
        d.css('padding-top', height - d.find('div').height());
    });
}

Demo: http://jsfiddle.net/Guffa/Lunxbr6p/2/

The boxes in the demo are editable, so you can change the text and see how the boxes resize.



来源:https://stackoverflow.com/questions/30016844/javascript-too-fast-for-dom-manipulation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!