一开始觉得这个问题很简单,每插入一张图片之前比较各个“流”的高度,找个最短的放进去就行了。后来发现没那么简单。 直接想到的问题就是图片未加载完成是得不到图片的完整高度的,后来找到dom的naturalHeight属性,可以在图片未加载成功时就获取到图片高度
然后开始常规操作,用nextTick递归把图片数据插入到对应的数组中,但是nextTick中获取图片dom的naturalHeight是获取不到的,但是页面中图片就算未加载完成是可以获取到的。猜想是vue渲染完图片的dom时执行nextTick,图片刚开始加载,这时候接口还没有获取到计算naturalHeight属性相关的数据。所以这条路就是走死了,因为这个方法下图片什么时候加载完成无法监控,都是第一张图片插入之后第二张图片放哪里没法计算。
第一时间想到的就是setInterval,然后不到一秒钟就被自己否决了,丑而且耗费性能,宁愿在数据库里扩展width、height字段也不用这个方法(我还真的扩展了)。但是不太服气,然后寻找满是广告的度娘,发现一个方法,既然之前问题出在图片什么时候加载完成无法监控,那就用image.onload()方法获取图片信息,然后在回调里面丁零当啷一顿操作拼好dom,插入到页面中。 偷来的代码
sort(j) {if (j < this.moments.length) {let that = this;// 创建Image类var newImg = new Image();// 获取要加载的图片地址newImg.src ="http://lanyue.ink:8123/images/" +(Math.floor(Math.random() * 15) + 1) +".png";// 图片加载完成后(异步)newImg.onload = () => {// 四个管道的高度 var arr = [that.$refs.piping0.offsetHeight,that.$refs.piping1.offsetHeight,that.$refs.piping2.offsetHeight,that.$refs.piping3.offsetHeight];//获取管道最小高度var min = arr.indexOf(Math.min.apply(Math, arr));// 添加卡片的模板var html =`<div class="card"><img src=` + newImg.src + `><div><img src="http://lanyue.ink:8123/images/avatar.jpg" alt=""><div>` + this.moments[j].id + " " + this.moments[j].content + `</div></div></div>`;//给最小的管道添加卡片if (min == 0) {that.$refs.piping0.innerHTML += html;} else if (min == 1) {that.$refs.piping1.innerHTML += html;} else if (min == 2) {that.$refs.piping2.innerHTML += html;} else if (min == 3) {that.$refs.piping3.innerHTML += html;}that.sort(j + 1);};}
},
复制代码
作者如果看到了不要喷我,都走到这一步了,为什么还要用插入html的方式,拿到图片的宽高,加一个计算“流”高度的字段,插入一张图就加一个图片的高度,这样也就不用再从dom中获取“流”的高度。这样的好处有两个,一是减少一次dom的查询,二是如果页面需要响应式,插入html的方式其实是无法通过直接改变数据操作dom,违背了vue的本意(对于两个方法的性能消耗有机会多做研究,感觉起来应该是我的方法美一点)。
getImageList() {let that = this;imageService.getImageList(this, {params: {categoryId: 37}}).then(function (result) {if (result.code === 0) {that.tempImage = result.data;that.pushImage(0);}});
},pushImage(index) {if (index >= this.tempImage.length) return;let img = new Image(), that = this;img.src = that.$store.state.imageURL + that.tempImage[index].url;img.onload = () => {let min = that.imageHeight[0], imageIndex = 0;that.imageHeight.forEach(function (item, _index) {if (min > item) {min = item;imageIndex = _index;}});that.imageHeight[imageIndex] += img.naturalHeight / img.naturalWidth;that.imageList[imageIndex].push(that.tempImage[index]);that.pushImage(index + 1);}
},
复制代码
最后再加上一段监控页面位置函数,实现拉到底部加载图片的功能
pullDown() {// 获取滚轮位置this.height1 = window.pageYOffset ||document.documentElement.scrollTop ||document.body.scrollTop;// 文档高度this.height2 = document.body.scrollHeight;// 可视区域// 设置compatMode兼容IEthis.height3 = document.compatMode === "CSS1Compat"? document.documentElement.clientHeight: document.body.clientHeight;// 如果滚动到最低(这里设置离最底还有100距离才触发函数)// available条件是为了防止触底时一直不断地请求。因此,请求一次后available设为0,直到滚动到离底部超过100距离(即数据加载玩后)才设为1if (this.height3 + this.height1 >= this.height2 - 100 && this.available) {this.available = false;//请求下一页,如果当前页等于最大页,直接返回if (this.pagination.currentPage >= this.pagination.totalPage) {this.footerVisible = true;return;}this.pagination.currentPage++;this.getImagePage();} else if (this.height3 + this.height1 < this.height2 - 100) {this.available = true;}
}复制代码
最终效果图
参考文章:来自MarieDreamer blog.csdn.net/qq_33514421…