需求描述
架构:原生js及jQuery
需求:需要根据网页DOM及资源都加载后的布局(高度等)来调整页面
方案:监听图片的load事件,都加载完毕后,执行后续js逻辑
考虑到动态添加的dom中也可能存在图片,对这些图片也需要监听load事件
1 load事件绑定问题
1.1 在img标签中定义onload事件
...<img src="img/img_1_1.png" onload="testLoad()"/>...<script>testLoad = () => {console.log('loaded')}</script>
某些情况下不能稳定触发,尚未复现bug找到原因
另外,此方案需要对每个动态插入的img指定onload方法。
如要实现对 “所有图片加载完毕” 的判断,还需新增:计数、指定error方法等逻辑。代码复杂化,不可取
1.2 直接绑定img事件
...<img src="img/img_1_1.png"/>...<script>$('body').on('load', 'img', function(){console.log('loaded')})</script>
经过测试,无法通过on给img绑定load事件(click等事件可以),在$(document).ready()中绑定也无法生效。
没找到原因
$('img').on('load', testLoad)
只能监听当前DOM树中的img
2 方案
window.onload内执行后续js逻辑,确保dom及资源加载完毕
为动态添加的img逐一绑定load事件
...<img class="test-img" src="img/test.jpg"/>...<script>testLoad = (dom) => {console.log('loaded')}myfunc = () => {const imgList = [{'title': 'test1', 'src': 'img/test1.jpg'},{'title': 'test2', 'src': 'img/test2.jpg'},]imgList.forEach((img, idx) => {let tmpImgDom = $(`<img src="${img.src}"/>`)tmpImgDom.load(() => testLoad(tmpImgDom))$('body').append(tmpImgDom)})}$(window).load(){myfunc()}</script>
由于将逻辑放在window.onload中,可省去1.1.2的过程:原HTML页面中图片资源已经加载完毕,只需监听动态插入的图片资源即可
不利之处在于会延长页面的处理时间。由于动态加载的图片的高度决定着后续页面的处理,所以,准确监听图片加载状态是必须要做到的,没有更好方案的情况下只能在此延长一点时间。
3 代码
demo中的图片自行替换
<!DOCTYPE html><html><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><meta name="renderer" content="webkit"><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"><script src="/jquery-2.1.1.min.js"></script><style>img {height: 80px;display: block;margin-bottom:5px;}</style></head><body></body><script>let IMG_NUM = 0let IMG_ERR = false$(window).load(function(){myfunc(laterFunc)})// 动态插入img标签myfunc = (callback) => {const imgList = [{'title': 'test', 'img': 'img/test.jpg'},{'title': 'test1', 'img': 'img/test11.jpg'},{'title': 'test2', 'img': 'img/test2.jpg'},{'title': 'test3', 'img': 'img/test3.jpg'}]if(imgList.length > 0) {addImgDoms(imgList)} else {callback()}// 测试// 动态插入img、设定监听事件都是异步的// 多次动态插入操作之间的时间间隔不会导致countImgNum中IMG_NUM == 0的重复触发// addImgDoms([// {'title': 'test', 'img': 'img/test.jpg'},// {'title': 'test1', 'img': 'img/test1.jpg'},// ])// let tmpDate = new Date()// console.log(tmpDate.getSeconds() + '.' + tmpDate.getMilliseconds())// for(let i = 0; i < 1000000000; i++) {}// tmpDate = new Date()// console.log(tmpDate.getSeconds() + '.' + tmpDate.getMilliseconds())// addImgDoms([// {'title': 'test2', 'img': 'img/test2.jpg'},// {'title': 'test3', 'img': 'img/test3.jpg'},// ])}// 插入img标签addImgDoms = (list) => {list.forEach(img => {let tmpImgDom = $(`<img src="${img.img}" data-title="${img.title}"/>`)dealInsertImgDom(tmpImgDom)$('body').append(tmpImgDom)})}// 处理插入的imgdealInsertImgDom = (dom) => {IMG_NUM++dom.load(() => testLoad(dom))dom.error(() => testError(dom))}// 绑定load事件testLoad = (dom) => {console.log('loaded', dom.attr('data-title'))countImgNum()}// 绑定error事件testError = (dom) => {console.log('load error', dom.attr('data-title'))IMG_ERR = truecountImgNum()}// 倒计数countImgNum = () => {IMG_NUM--if(IMG_NUM == 0) {laterFunc()}}// 后续js逻辑laterFunc = () => {console.log('[end] has error:', IMG_ERR)}</script></html>