用vue來實現一個瀑布流效果,加載網絡圖片,同時有下拉刷新和上拉加載更多功能效果。而後針對這幾個效果的實現,捋下思路:css
先看個效果動圖:vue
靜態截圖:ios
本地準備一個json文件數據,放在項目public文件夾下。注意,本地測試數據必須放在public文件夾下,網絡請求時才能請求到數據,這是vue3.x。新增長一個axios依賴包,用來進行網絡請求。部分截圖,及關鍵代碼:git
//數據請求 getDataList(){ this.$axios.get("/json/dataList.json").then((res)=>{ let list = res.data.data ? res.data.data: []; if (list.length > 0){ //從list中取pageSize條數據出來 var tempList = []; for (let i = 0; i < this.pageSize; i++){ if (list.length > 0){ let tempIndex = parseInt(Math.random() * 1000) % list.length; tempList.push(list[tempIndex]); list.splice(tempIndex, 1); } } this.loadImagesHeight(tempList); //模擬預加載圖片,獲取圖片高度 } else { this.loadImagesHeight(list); } }).catch((res)=>{ console.log("..fail: ", res); this.$toast.clear(); this.isLoading = false; //下拉刷新請求完成 this.loading = false; //上拉加載更多請求完成 }) },
獲取數據後,遍歷數據數組,預加載圖片,計算圖片縮放後的高度,存儲起來。同時因爲圖片加載是異步加載,因此用變量計數,當最後一個圖片加載完成後,開始渲染頁面。github
loadImagesHeight(list){ var count = 0; //用來計數,表示是否全部圖片高度已經獲取 list.forEach((item, index)=>{ //建立圖片對象,加載圖片,計算圖片高度 var img = new Image(); img.src = item.cover; img.onload = img.onerror = (e)=>{ count++; if (e.type == 'load'){ //圖片加載成功 //計算圖片縮放後的高度:圖片原高度/原寬度 = 縮放後高度/縮放後寬度 list[index].imgHeight = Math.round(img.height * this.boxWidth / img.width); // console.log('index: ', index, ', load suc, imgHeiht: ', list[index].imgHeight); } else{ //圖片加載失敗,給一個默認高度50 list[index].imgHeight = 50; console.log("index: ", index, ", 加載報錯:", e); } //加載完成最後一個圖片高度,開始下一步數據處理 if (count == list.length){ this.resolveDataList(list); } } }) },
全部圖片經過預加載獲取圖片高度後,開始渲染頁面。而後遍歷全部圖片所在盒子標籤,獲取盒子高度,設置每一個盒子的絕對定位。json
resolveDataList(list){ //處理數據 //下拉刷新,清空原數據 if (this.pageIndex <= 1){ this.itemCount = 0; this.dataList = []; this.lastRowHeights = [0, 0]; //存儲每列的最後一行高度清0 } if (list.length >= this.pageSize){ this.pageIndex++; //還有下一頁 } else{ this.finished = true; //當前tab類型下全部數據已經加載完成 } //合併新老兩個數組數據 this.dataList = [...this.dataList, ...list]; //判斷頁面是否有數據 this.haveData = this.dataList.length > 0 ? 2 : 1; this.isLoading = false; //下拉刷新請求完成 this.loading = false; //上拉加載更多請求完成 console.log("...datalist: ", this.dataList); console.log("...this.isLoading: ", this.isLoading) this.$nextTick(()=>{ setTimeout(()=>{ //渲染完成,計算每一個item寬高,設置標籤座標定位 this.setItemElementPosition(); this.isLoading = false; //下拉刷新請求完成 this.loading = false; //上拉加載更多請求完成 }, 1000) }); }, //獲取每一個item標籤高度,設置item的定位 setItemElementPosition(){ let parentEle = document.getElementById('data-list-box'); let boxEles = parentEle.getElementsByClassName("data-item"); for (let i = this.itemCount; i < boxEles.length; i++){ let tempEle = boxEles[i]; //上一個標籤最小高度的列索引 let curColIndex = this.getMinHeightIndex(this.lastRowHeights); let boxTop = this.lastRowHeights[curColIndex] + this.boxMargin; let boxLeft = curColIndex * (this.boxWidth + this.boxMargin) + this.boxMargin; tempEle.style.left = boxLeft + 'px'; tempEle.style.top = boxTop + 'px'; this.lastRowHeights[curColIndex] = boxTop + tempEle.offsetHeight; // console.log('i = ', i, ', boxTop: ', boxTop, ', eleHeight: ', tempEle.offsetHeight); } this.itemCount = boxEles.length; //修改父級標籤的高度 let maxHeight = Math.max.apply(null, this.lastRowHeights); parentEle.style.height = maxHeight + 'px'; this.$toast.clear(); console.log("...boxEles: ", boxEles.length, ", maxH: ", maxHeight); },
其餘頁面中以下拉刷新,和上拉加載更多等功能,使用了有讚的組件庫中的PullRefresh 和 List這一套組合組件。感受效果挺棒的,使用步驟也簡單。另外就是在頁面渲染時,會出現頁面閃爍的現象,後面使用了一個css動畫處理了這個現象,效果好了不少。可是在第一次加載的時候,仍是有輕微的閃爍現象。等後面找到更好的方法,再更新。axios
完整效果DEMO地址:https://github.com/xiaotanit/tan_vue/blob/master/src/views/PageWaterFall.vue數組