前面文章《》和《》已经介绍了瀑布流的基本实现的一种方法,虽然是在vuejs中实现的,可是实际上也可以把这段代码扒出来,在我们的任何项目中使用,并不局限于vuejs。
我也在项目中用这段代码实现了这种瀑布流。
后来发现一个问题,就是瀑布流布局会在每次刷新之后,排序发生变化,如果讲究一点的话,其实并没有什么特别大的影响,可是如果追求精益求精的话,确实不太理想。
看一下,瀑布流实现的关键性代码:
$("#items").children("li").each(function (index, val) { var $this = $(this); var $img = $this.find("img").first(); $img.on("error", function () { $img.attr("src", "../src/assets/images/default.png"); }); if ($img.get(0).complete) { addItems(); } else { $img.on("load", function () { addItems(); }); } function addItems() { if(_this.leftHeight <= _this.rightHeight){ $l.append($this); _this.leftHeight = $l.height(); }else{ $r.append($this); _this.rightHeight = $r.height(); } } $.refreshScroller();});
其中的addItems就是布局瀑布流的,但是当前存在的问题就是:当从后台取回数据之后,在id="items"的ul中渲染每一项列表时,一旦图片加载完成,就立马将其布局到页面中,这就必然导致每次刷新之后页面布局排序的顺序有所不同,因为我们没有办法预计哪条数据中的图片加载先完成。
如此,如果需要修复这个问题的话,似乎只有一个可提供的方案,等待所有图片在<ul id="items"></ul>中加载完成,然后在按顺序布局到页面中。
定义一个全局变量:
imgs: { imgLoad: [], loadNums: 0}
在数据请求回来之后,把新请求回来的数据赋值给imgs.imgLoad,以保证imgs.imgLoad里面所存储的数据都是刚刚请求回来的数据,然后在<ul id="items"></ul>渲染之前,将imgs.loadNums = 0;重新赋值为0,然后<ul id="items"></ul>的列表li每次渲染加载img成功之后imgs.loadNums++,当imgs.loadNums值等于imgs.imgLoad的数组长度的时候,再开始页面布局。
$("#items").children("li").each(function (index, item) { var $this = $(item); var _img = $(item).find("img").first(); _img.on("error", function () { _img.attr("src", "../src/assets/images/default.png"); }); _this.leftHeight = $l.height(); _this.rightHeight = $r.height(); if(_img.get(0).complete){ _this.imgs.loadNums++ } else { _img.on("load", function () { _this.imgs.loadNums++ waterfallLayer(); }) } }) waterfallLayer() function waterfallLayer() { if (_this.imgs.loadNums == _this.imgs.imgLoad.length) { $("#items").children("li").each(function (index, item) { if(_this.leftHeight <= _this.rightHeight){ $l.append($(item)); _this.leftHeight = $l.height(); }else{ $r.append($(item)); _this.rightHeight = $r.height(); } }) } }
就此保证了,不管怎么刷新页面,数据排序都是一致的。