JavaScript如何获取图片onload回调中的宽高比 解决逻辑不生效问题
问题根因
你遇到的问题本质是异步执行时序和循环变量作用域两个问题共同导致的:
Image.onload是异步回调,浏览器需要等待图片资源加载完成才会触发该函数,而你外层的while循环是同步代码,会一次性执行完成。所有循环中声明的onload回调,都要等到循环完全结束后才会触发,此时你代码中用到的nump计数变量已经是循环结束的最终值,根本找不到对应编号的DOM元素,赋值自然不生效。- 你在
onload内部定义的divi是局部变量,外部作用域本来就无法访问。你说把判断逻辑放到onload外可以执行,大概率是碰巧命中了图片缓存、或者变量全局污染导致的巧合,不符合JS的执行逻辑。
解决方案
推荐用异步语法简化逻辑,避免回调嵌套问题:
步骤1:封装获取图片宽高比的异步函数
function getImageRatio(imgUrl) { return new Promise((resolve, reject) => { const img = new Image() // 加载成功返回宽高比 img.onload = () => resolve(img.naturalWidth / img.naturalHeight) // 加载失败抛出错误 img.onerror = reject img.src = imgUrl // 如果有跨域需求可以开启下面的配置,同时需要图片服务支持跨域 // img.crossOrigin = 'anonymous' }) }
步骤2:把同步while循环改为异步循环
因为要等待图片加载的异步结果,不能用纯同步的while逻辑,改成异步函数包裹的循环即可:
// 参数为你要处理的图片地址数组 async function batchProcessImages(imageList) { let nump = 0 // 对应你原有的循环计数变量 // 替换成你原有的while循环判断条件 while (nump < imageList.length) { const currentImgDir = imageList[nump] // 等待图片加载完成,拿到当前图片的宽高比 const divi = await getImageRatio(currentImgDir) const targetEl = node.getElementById("myImage-" + nump) if (divi > 1) { targetEl.dataset.size = "1600x1200" } else { targetEl.dataset.size = "1200x1600" } nump++ } } // 调用函数执行逻辑,传入你的图片地址数组 batchProcessImages(你的图片地址数组)
兼容方案(不使用async/await)
如果你的运行环境不支持ES7的async/await语法,可以用立即执行函数形成闭包,保存每次循环的nump值:
let nump = 0 // 替换成你原有的while循环判断条件 while (/* 原判断条件 */) { // 用立即执行函数闭包保存当前迭代的nump和图片地址 (function(currentNump, currentImgDir) { const newimage = new Image() newimage.src = currentImgDir newimage.onload = function() { const divi = this.naturalWidth / this.naturalHeight const targetEl = node.getElementById("myImage-" + currentNump) if (divi > 1) { targetEl.dataset.size = "1600x1200" } else { targetEl.dataset.size = "1200x1600" } } })(nump, ImageDir) // 把当前循环的计数和图片地址传入闭包 nump++ }
内容的提问来源于stack exchange,提问作者Félix Lauzon
相关产品推荐
相关产品推荐

