如何解决JavaScript中动态加载图片宽高后续获取为0的问题
解决naturalWidth/naturalHeight几分钟后变为0的问题
嘿,这个问题我之前踩过坑!大概率是浏览器的内存缓存机制在搞事情——当页面闲置几分钟后,浏览器会把没被活跃引用的图片资源从内存里释放掉,这时候再去读naturalWidth和naturalHeight自然就返回0了。给你几个靠谱的解决办法:
1. 确保在图片完全加载后读取宽高(核心方案)
很多时候你首次能拿到值,是因为图片刚好加载完成,但后续浏览器释放缓存后,直接读取属性就会失败。所以一定要在图片的load事件触发后再获取宽高,即使是缓存的图片,load事件也会正常触发(除非资源被彻底清理)。
let img_div = '<img id="view_img_0" class="pointer micro_otpt view_port_img" src="https://picsum.photos/id/877/200/300" alt="user">'; $('#view_port_img').html(img_div); const myImg = document.querySelector("#view_img_0"); // 封装获取宽高的逻辑 function getImgDimensions() { const width = myImg.naturalWidth; const height = myImg.naturalHeight; console.log('图片宽高:', width, height); // 这里处理你的业务逻辑 } // 先检查图片是否已经加载完成 if (myImg.complete) { getImgDimensions(); } else { // 监听load事件 myImg.addEventListener('load', getImgDimensions); // 别忘了处理加载失败的情况,避免一直等待 myImg.addEventListener('error', () => { console.error('图片加载失败,请检查地址'); }); }
2. 把宽高缓存起来,避免重复读取natural属性
既然首次加载能拿到正确值,不如直接把宽高存起来——可以存在图片元素的dataset属性里,或者全局变量(如果场景合适的话)。后续需要用的时候直接取缓存的值,不用再去读可能已经失效的naturalWidth/naturalHeight。
let img_div = '<img id="view_img_0" class="pointer micro_otpt view_port_img" src="https://picsum.photos/id/877/200/300" alt="user">'; $('#view_port_img').html(img_div); const myImg = document.querySelector("#view_img_0"); // 存储宽高到dataset function storeDimensions() { myImg.dataset.imgWidth = myImg.naturalWidth; myImg.dataset.imgHeight = myImg.naturalHeight; } // 首次加载时存储 if (myImg.complete) { storeDimensions(); } else { myImg.addEventListener('load', storeDimensions); } // 几分钟后需要用宽高时 function getCachedDimensions() { const width = parseInt(myImg.dataset.imgWidth, 10); const height = parseInt(myImg.dataset.imgHeight, 10); if (width && height) { return { width, height }; } // 如果缓存丢失,重新加载图片获取(加时间戳避免缓存) return new Promise((resolve, reject) => { const newImg = new Image(); newImg.src = `${myImg.src}?t=${Date.now()}`; newImg.onload = () => { const newWidth = newImg.naturalWidth; const newHeight = newImg.naturalHeight; // 更新缓存 myImg.dataset.imgWidth = newWidth; myImg.dataset.imgHeight = newHeight; resolve({ width: newWidth, height: newHeight }); }; newImg.onerror = reject; }); }
3. 避免频繁替换DOM导致引用失效
如果你的代码后续会重新替换#view_port_img里的HTML,那原来的myImg引用就指向了被移除的DOM元素,这时候读取属性肯定是0。建议不要每次都用html()替换整个内容,而是复用已有的图片元素:
// 先检查图片元素是否存在 let myImg = document.querySelector("#view_img_0"); if (!myImg) { // 不存在就创建 myImg = document.createElement('img'); myImg.id = 'view_img_0'; myImg.className = 'pointer micro_otpt view_port_img'; myImg.alt = 'user'; $('#view_port_img').append(myImg); } // 只更新src,不替换整个DOM myImg.src = "https://picsum.photos/id/877/200/300"; // 再监听load事件获取宽高(和方法1的逻辑一致) function getImgDimensions() { console.log(myImg.naturalWidth, myImg.naturalHeight); } if (myImg.complete) { getImgDimensions(); } else { myImg.addEventListener('load', getImgDimensions); }
总结
最稳妥的是结合方法1和方法2:首次加载时通过load事件获取宽高并缓存,后续优先使用缓存的值;如果缓存意外丢失,再重新加载图片获取新的宽高。这样就能彻底解决几分钟后属性值变为0的问题啦!
内容的提问来源于stack exchange,提问作者Sweta Sharma
相关产品推荐
相关产品推荐

