Images loaded JavaScript - Using jQuery Masonry

2020-05-09 07:47发布

I am building a tumblr theme from scratch and I'm using masonry. Although, sometimes it overlaps pictures, it doesn't add any gutter, calculates top wrong, and I'm not sure of what's happening. I tried adding imagesloaded library but I don't think it's woking since it's still overlapping pictures, etc, sometimes.

Images width and height are defined on the CSS since they're all the same width but different heights.

HTML

<div class="masonry js-masonry"  data-masonry-options='{ "isFitWidth": true, "gutter": 14}' id="content">

 {block:Posts}
 <div class="container" id="{postID}">

      {block:Photo}
      <div class="photo inner">
        <a href="{permalink}">
          <img src="{block:indexpage}{PhotoURL-500}{/block:indexpage}{block:permalinkpage}{PhotoURL-HighRes}{/block:permalinkpage}" alt="{PhotoAlt}">
        </a></div>
        {/block:Photo}
      </div>

      {/block:Posts}          
    </div>

JS

var container = document.querySelector('#content');
var msnry;
imagesLoaded( container, function() {
  msnry = new Masonry( container );
});

2条回答
老娘就宠你
2楼-- · 2020-05-09 08:33

Please use following code with imagesloaded plugin:

jQuery(document).ready(function(){
    imagesLoaded( 'body', function() {
        jQuery('.js-masonry').masonry('layout');
    });
});

It is the easiest solution when you use masonry as <div class="masonry js-masonry" data-masonry-options='{ "isFitWidth": true, "gutter": 14}' id="content">....</div>

查看更多
淡お忘
3楼-- · 2020-05-09 08:40

I had a similar issue with Masonry, with a project that is now unfortunately offline, so I cannot give you a URL. I dug up the code, and my workaround was:

$(document).ready(function() {
    // Count the images in the masonry div
    num_images = $("#content img").length

    // Set a counter to track how many have loaded.
    img_counter = 0;

    // As each image loads, increment the counter. If they are all loaded,
    // call masonry.
    $("#content img").on('load', function() {
        img_counter++;
        if (img_counter == num_images) {
            // And I seem to have settled on calling masonry twice to help fix the glitch!
            // This is as I found it in my code.
            $("#content").masonry('reloadItems').masonry();
        }
    });
});

That's jQuery-flavoured; it doesn't look like you're using jQuery, but I hope it helps.


Update:

I just found this section of the masonry docs, which I don't remember from my time with Masonry:

http://masonry.desandro.com/appendix.html#imagesloaded

If I wait for your tumblr page to finish loading, then open the console, and type in:

var $tumblelog = $('#content');
$tumblelog.masonry('layout')

then the layout works and the overlap vanishes. So if we wait long enough, then calling the layout method fixes your problem. The challenge is to work out what we need to wait for! Some options:

  1. Try the imagesLoaded or my image counter approach, but use $tumblelog.masonry('layout')
  2. the URL above says web fonts also interfere with Masonry layout, so install the webfontloader and call ('layout') only when the images and the fonts have loaded (promises can help with this)
  3. Just use a timeout - a bit hacky!

    window.setTimeout(function() { $tumblelog.masonry('layout') }, 1000)

and adjust the value of the timeout until it works.


Second update

Here's a fiddle showing how to redo the layout of Masonry after fonts and images have both loaded:

http://jsfiddle.net/sifriday/5xotLj23/3/

I don't know how tumblr loads content into your template, but I reckon the problem arises due to a mess of complexity associated with inserting content into the DOM, so I have tried to recreate that by adding your images using JS. Within the fiddle, there's a JS line that if you comment it out then re-run the fiddle, seems to recreate the overlap problem.


Quick Tumblr Hack

In your template where you are working with docReady, try this:

docReady( function() {
    window.setTimeout(function() {
        $("#content").masonry('layout');
    }, 2000);
});

After two seconds that will call Masonry to redo the layout. If if works, then you know the problem is definitely something to do with waiting for the right combination of things to load.


Essential code

To integrate my fiddle,

Remove your CSS that loads the Google Font.

Use this JS:

docReady(function() {

    // Asynchronously load the Google web fonts script, as if it was included in the 
    // <head> element.
    var wf = document.createElement('script');
    wf.src = ('https:' == document.location.protocol ? 'https' : 'http') +
      '://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js';
    wf.type = 'text/javascript';
    wf.async = 'true';
    var s = document.getElementsByTagName('script')[0];
    s.parentNode.insertBefore(wf, s);

    // When we have the script, load the fonts.
    wf.onload = function() {
        WebFont.load({

            // Put your font families here. You can get these from the usual Google Fonts page;
            // from the bit where you copy-paste the CSS URL, select the 'JavaScript' tab and
            // you will see the families definition for the fonts you have selected.
            google: { families: [ 'Arvo::latin' ] },

            // When the font is loaded, resolve its Deferred object.
            active: function() {
                console.log("Fonts active")
                fonts_loaded.resolve()
            }
        });
    }

    // Set up two Deferred objects, to track images and fonts.
    var images_loaded = $.Deferred()
    var fonts_loaded = $.Deferred()

    // When both promises complete, redo the Masonry layout.
    $.when(images_loaded, fonts_loaded).done(function() {
        console.log("Redoing Masonry");
        // Try commenting out this line; without it, masonry won't find any images
        // and the layout should be standard HTML.
        $("#content").masonry('reloadItems');

        // Try commenting out this line; without it, the layout algorithm should be
        // messed up, and the images will overlap.
        $("#content").masonry('layout');
    });

    // Deal with the image loading process using Masonry's imagesLoaded plugin.
    $("#content").imagesLoaded(function() {
      console.log("Images loaded")
      images_loaded.resolve();
    });
});

Update the font definitions in this line:

google: { families: [ 'Arvo::latin' ] },
查看更多
登录 后发表回答