1. 程式人生 > 程式設計 >vue實現網路圖片瀑布流 + 下拉重新整理 + 上拉載入更多(步驟詳解)

vue實現網路圖片瀑布流 + 下拉重新整理 + 上拉載入更多(步驟詳解)

一、思路分析和效果圖

  用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: ",", 載入報錯:",e);
   }

   //載入完成最後一個圖片高度,開始下一步資料處理
   if (count == list.length){
    this.resolveDataList(list);
   }
   }
  })
},

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 = 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);
  },

2.4、其他說明

  其他頁面中如下拉重新整理,和上拉載入更多等功能,使用了有讚的元件庫中的PullRefresh 和 List這一套組合元件。感覺效果挺棒的,使用步驟也簡單。另外就是在頁面渲染時,會出現頁面閃爍的現象,後面使用了一個css動畫處理了這個現象,效果好了很多。但是在第一次載入的時候,還是有輕微的閃爍現象。等後面找到更好的方法,再更新。

完整效果DEMO地址:https://github.com/xiaotanit/tan_vue/blob/master/src/views/PageWaterFall.vue

總結

以上所述是小編給大家介紹的vue實現網路圖片瀑布流 + 下拉重新整理 + 上拉載入更多(步驟詳解),希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回覆大家的。在此也非常感謝大家對我們網站的支援!
如果你覺得本文對你有幫助,歡迎轉載,煩請註明出處,謝謝!