Laravel项目中jQuery过滤器调用hide()后Masonry.js布局异常求解
异常原因
- Masonry调用时机错误:你在隐藏所有元素后立刻调用了一次
$(".grid").masonry(),此时所有元素均为不可见状态,Masonry计算时拿到的宽高都是0,布局基准直接错误。 - 未通知Masonry元素状态变更:元素显隐调整完成后,你直接调用
.masonry()没有触发正确的重排逻辑,Masonry默认会复用初始的元素集合和旧的布局缓存,不会自动识别最新显示的元素。 - 重复初始化打乱实例状态:你用HTML的
data-masonry属性自动初始化了Masonry实例,后续反复调用无配置的.masonry()相当于重复初始化,直接打乱了实例的内部状态。 - 图片加载时序问题:瀑布流布局高度依赖元素的实际宽高,未等图片加载完成就计算布局会出现高度偏差,你遇到的“仅勾选左上角卡片分类时布局正常”的现象,本质是第一张卡片的图片加载速度最快,碰巧在布局计算前完成了加载。
修复方案
调整JS代码如下,使用Masonry官方提供的reloadItems和layout方法触发正确重排:
$(function(){ // 提前获取Masonry实例,避免重复初始化 const $grid = $(".grid"); const masonryInstance = $grid.data('masonry'); $('form').find("input").on('change',function(){ let selected = []; $('form').find("input").each(function(){ if($(this).is(":checked")){ selected.push($(this).val()); } }) // 统一处理元素显隐 $(".products-by-room > .grid-item").each(function(){ const $item = $(this); const category = $item.attr('data-category'); const categorySplitted = category.split(' '); let shouldShow = false; categorySplitted.forEach((cat)=>{ if(selected.indexOf(cat) !== -1){ shouldShow = true; } }); // 无选中项时展示全部卡片 shouldShow = selected.length === 0 ? true : shouldShow; $item.toggle(shouldShow); }); // 等待DOM显隐更新完成后,重新加载元素并触发重排 setTimeout(()=>{ masonryInstance.reloadItems(); masonryInstance.layout(); },0); // 兼容图片未加载完成的场景,等所有显示的图片加载完成后再重排一次 $grid.imagesLoaded().progress( function() { masonryInstance.layout(); }); }); });
如果需要使用imagesLoaded能力,可以在Masonry引入代码后新增一行资源引入:
<script src="https://unpkg.com/imagesloaded@5/imagesloaded.pkgd.min.js"></script>
内容的提问来源于stack exchange,提问作者mlila_p
相关产品推荐
相关产品推荐

