前面寫過vuejs實現的瀑布流佈局,《vuejs實現瀑布流佈局(一)》和《vuejs實現瀑布流佈局(二)》也確實實現了瀑布流佈局,可是這個是基於SUI-Mobile實現的無限滾動。javascript
近日稍有空閒,回頭從新實現了一下移動端的瀑布流佈局,擺脫了移動端UI框架的束縛。css
移動端的適配,採用的是adaptive-version2.js,而無限加載採用的是Vue Scroller。html
最終實現的效果大體以下:vue
解決了無限滾動和移動端適配的問題,瀑布流也就只剩下一個難點,怎麼樣讓高度不盡相同的圖片可以按左右順序排列下來,還不至於錯亂太多,相差太大。java
事實上css也已經爲咱們提供瞭解決方案,可是css的方案有一個巨大的缺陷在於:一旦圖片發生變更,不論增長仍是減小,或者說圖片資源自己發生變化,他會將總體全部圖片的位置進行重排。就是說只要咱們動了任意一張圖片,其佈局可能會徹底不一樣。ios
而js的瀑布流,主流方案彷佛只有兩種(具體更多的方案沒有研究),一個利用絕對定位,一個分左右兩欄(或者多欄),每欄內部垂直佈局,而依據圖片高度的不一樣,將其放入適合的欄目內,實現瀑布流。git
咱們這裏採用的就是左右兩欄的佈局。github
<div class="waterfalls"> <ul> <li class="photo" v-for="item in waterfallsLeft" :key="item.id + item.albumId+Math.random()"> <a href="javascrip:;"> <img :src="item.src" alt=""> </a> <div class="desc-info"> <p>編號:<span>{{item.albumId}}</span></p> </div> <div class="thumbnail"> <div class="thumbnail-desc"> <p>{{item.title}}</p> <span>{{item.thumbnailUrl}}</span> </div> <div class="praise active"> <div> <i>贊</i> <span>{{item.albumId}}</span> </div> </div> </div> </li> </ul> <ul> <li class="photo" v-for="item in waterfallsRight" :key="item.id + item.albumId+Math.random()"> <a href="javascrip:;"> <img :src="item.src" alt=""> </a> <div class="desc-info"> <p>編號:<span>00001</span></p> </div> <div class="thumbnail"> <div class="thumbnail-desc"> <p>雙語小學</p> <span>詹天佑</span> </div> <div class="praise active"> <div> <i>贊</i> <span>92</span> </div> </div> </div> </li> </ul> </div>
div.waterfalls做爲外層包裹,而裏面的兩個ul,就是兩欄,li就是每一張圖片所對應的數據。ul寬度各佔50%,而後浮動。剩下的就是怎麼樣讓個張圖片自動歸位,進入waterfallsLeft和waterfallsRight。json
首先請求數據:axios
getData(done){ let _this = this; axios.get("https://jsonplaceholder.typicode.com/photos", {page: this.page}) .then(res=>res.data) .then(res => { let counts = res.slice((this.page-1) * this.pageCount, this.page * this.pageCount) // console.log(counts.length) counts.forEach(item => { item.src ='http://cued.xunlei.com/demos/publ/img/P_'+ this.randomNum()+ '.jpg' }); this.page++; this.itemsLen = counts.length; this.judgeAllLoaded(counts) self.bottom = self.bottom + 10; if(done) done(); }) }, randomNum(){ // 三位數隨機數,162之內 let random = Math.floor(Math.random() * 162) return random = random < 10 ? '00'+random : random < 100 ? '0'+random : ''+random; },
請求的是https://jsonplaceholder.typicode.com/photos,有不少數據能夠進行一些模擬請求,可是其返回的圖片都是相同大小的,因此爲其添加圖片資源,item.src ='http://cued.xunlei.com/demos/publ/img/P_'+ this.randomNum()+ '.jpg'。
有了數據,就得按照圖片在相同寬度的狀況下,高度不一樣,將其分組分別進入左右兩欄this.judgeAllLoaded(counts)。
judgeAllLoaded(items){ // 判斷全部圖片是否加載完成 let _this = this; items.forEach(item => { let IMG = new Image(); IMG.src = item.src; IMG.width = 100; IMG.onload = function () { _this.flag++; if(_this.leftHeight <= _this.rightHeight){ _this.leftHeight += IMG.height; _this.waterfallsLeft.push(item) }else{ _this.rightHeight += IMG.height; _this.waterfallsRight.push(item) } } }) }
這裏關鍵點在於:IMG.src = item.src; IMG.width = 100; IMG.onload = function;
爲IMG對象添加src,並設置相同寬度100,而後等待圖片加載完成onload,在圖片加載完成以後,判斷左右兩欄,哪一欄高度較低,該條數據進入哪一欄,這裏有一個不大不小的問題,就是因爲不肯定哪張圖片先加載完成,致使即便請求回來的數據相同,其排列的位置也未必相同,可是已經留下了解決flag做爲可能的解決方案。就是每加載完成一張圖片,flag自增,監聽flag的變化,當flag的值與請求回來的數據相等時,再進行數據分配,理論上應該能夠解決該問題,留待後面實現。
數據分配完成,其實瀑布流也已經實現了,剩下的就是無限滾動,繼續分配請求回來的數據了。
具體代碼能夠查看GitHub上的GitProjectWaterfalls。