一、思路分析和效果圖
用vue來實作一個瀑布流效果,加載網路圖片,同時有下拉重繪和上拉加載更多功能效果,然后針對這幾個效果的實作,捋下思路:
- 根據加載資料的順序,依次追加標簽展示效果;
- 選擇哪種方式實作瀑布流,這里選擇絕對定位方式;
- 關鍵問題:由于每張圖片的寬高不一樣,而瀑布流中要求所有圖片的寬度一致,高度隨寬度等比縮放,而且由于圖片的加載是異步延遲,在不知道圖片高度的情況下,每個圖片所在的item盒子不好絕對定位,因此在渲染頁面前先獲取所有圖片的高度,是解決問題的關鍵點!這里選擇用JS中的Image類,通過預加載圖片的方式提前獲取圖片寬高,另外通過一個臨時變數來計算是否所有圖片的高度已經得到,當所有的圖片高度獲取后,開始渲染頁面,
- 頁面渲染后,獲取所有圖片所在的盒子,回圈計算盒子的高度,開始設定每個盒子item的絕對定位,
- 頁面渲染時,會出現閃爍的現象,如何解決這個問題呢?這里用了一個影片樣式,不過在第一次加載的時候,還是會有一點閃爍的感覺,
- 然后就是下拉重繪和上拉加載更多的效果,這里用了有贊的vant組件PullRefresh和List這套組合組件來實作,
先看個效果動圖:

靜態截圖:

二、具體實作步驟
2.1、頁面結構設計,測驗資料準備,
本地準備一個json檔案資料,放在專案public檔案夾下,注意,本地測驗資料必須放在public檔案夾下,網路請求時才能請求到資料,這是vue3.x,新增加一個axios依賴包,用來進行網路請求,部分截圖,及關鍵代碼:

//資料請求 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; //上拉加載更多請求完成 }) },
2.2、預加載圖片,存盤圖片高度
獲取資料后,遍歷資料陣列,預加載圖片,計算圖片縮放后的高度,存盤起來,同時由于圖片加載是異步加載,所以用變數計數,當最后一個圖片加載完成后,開始渲染頁面,
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); } } }) },View Code
2.3、渲染頁面,設定絕對定位
所有圖片通過預加載獲取圖片高度后,開始渲染頁面,然后遍歷所有圖片所在盒子標簽,獲取盒子高度,設定每個盒子的絕對定位,
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 = https://www.cnblogs.com/tandaxia/p/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);
},
View Code
2.4、其他說明
其他頁面中如下拉重繪,和上拉加載更多等功能,使用了有贊的組件庫中的PullRefresh 和 List這一套組合組件,感覺效果挺棒的,使用步驟也簡單,另外就是在頁面渲染時,會出現頁面閃爍的現象,后面使用了一個css影片處理了這個現象,效果好了很多,但是在第一次加載的時候,還是有輕微的閃爍現象,等后面找到更好的方法,再更新,
完整效果DEMO地址:https://github.com/xiaotanit/tan_vue/blob/master/src/views/PageWaterFall.vue
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/156533.html
標籤:JavaScript
