如何在元素内容加载完成后执行函数 服务端加载更多场景实现
问题原因
- 普通div元素不支持
load事件:该事件仅会在window、图片、脚本、iframe这类需要加载独立外部资源的对象上触发,容器div本身没有资源加载逻辑,绑定后永远不会触发。 DOMContentLoaded事件仅在页面初始HTML文档解析完成时触发一次,后续动态插入的DOM不会再次触发该事件,绑定在动态容器上完全无效。setTimeout固定延时不可靠:DOM节点插入完成不代表内部图片资源加载完成,此时瀑布流拿不到卡片真实高度就会布局错乱;延时时长设太长又会阻塞交互,没有统一的合适值。- 额外代码bug:你当前
startIndex变量定义在loadMore函数内部,每次调用都会被重置为0再加5,永远只会拉取第一页的5条数据,需要把变量挪到函数外层。
解决方案
核心逻辑:新条目追加到瀑布流后,等待本次新增的所有图片资源全部加载完成(成功/失败都算),立刻触发布局刷新,不需要固定等待时长。
直接修改对应代码即可:
首先把分页索引挪到函数外层,修正分页逻辑:
let colc, colcUploadedByUser, colcPurchasedByUser; let searchQuery, filter; let startIndex = 0; // 挪到函数外层,保留分页进度
然后修改loadMore函数的追加逻辑,替换原有colc.append(itemsToAppend);部分的代码:
const loadMore = async function () { startIndex += 5; // 每次调用累加分页值 const searchQuery = searchForm.querySelector("input").value; const filter = searchForm.querySelector("select").value; const response = await fetch("load-more", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ startIndex, searchQuery, filter, }), }); const products = await response.json(); let itemsToAppend = []; products.forEach((product) => { const date = new Date(product.createdAt) .toISOString() .split("T")[0] .replaceAll("-", "/"); const htmlString = ` <img src="${product.optimizedImgUrl}" data-original-img-source="${product.imgUrl}" alt="article photo" class="articles-container__article-img"> <h2>${product.title}</h2> <p>${product.description} <button class="articles-container__highlight">Read more</button></p> <div class="articles-container__article-info separetor"><p>Price: ${product.price} $</p><p>Author: ${product.authorName} </p><p>Uploaded: ${date}</p> <p>Resolution: ${product.resolution}</p></div> <button class="btn-gray articles-container__button ai-c">Add <img src="img/shopping-cart.svg" alt="shopping cart"></button> `; const item = document.createElement("article"); item.className = "ver-spacer grid-item"; item.setAttribute("id", product._id); item.insertAdjacentHTML("beforeend", htmlString); itemsToAppend.push(item); }); // 追加新条目到瀑布流 colc.append(itemsToAppend); // 等待本次新增的所有图片加载完成 const newImages = itemsToAppend.flatMap(item => Array.from(item.querySelectorAll('img'))); await Promise.all(newImages.map(img => { // 图片已经加载过直接返回 if (img.complete) return Promise.resolve(); // 监听加载成功/失败事件,失败也不阻塞布局刷新 return new Promise(resolve => { img.addEventListener('load', resolve, { once: true }); img.addEventListener('error', resolve, { once: true }); }) })); // 所有图片加载完成,刷新瀑布流布局 reloadColcade(); };
补充说明:如果你的卡片没有图片、或者高度完全由固定尺寸的内容决定,不需要等图片加载的话,在
colc.append(itemsToAppend)之后直接调用reloadColcade()即可。Colcade的append方法本身是同步把DOM插入到列里的,DOM插入完成后就可以直接触发布局计算,之前布局错乱本质是图片加载前高度为0,加载完成后高度撑开但瀑布流没有重新计算导致的。
内容的提问来源于stack exchange,提问作者Oliwier
相关产品推荐
相关产品推荐

