vue實(shí)現(xiàn)網(wǎng)絡(luò)圖片瀑布流 + 下拉刷新 + 上拉加載更多(步驟詳解)
一、思路分析和效果圖
用vue來(lái)實(shí)現(xiàn)一個(gè)瀑布流效果,加載網(wǎng)絡(luò)圖片,同時(shí)有下拉刷新和上拉加載更多功能效果。然后針對(duì)這幾個(gè)效果的實(shí)現(xiàn),捋下思路:
根據(jù)加載數(shù)據(jù)的順序,依次追加標(biāo)簽展示效果;
選擇哪種方式實(shí)現(xiàn)瀑布流,這里選擇絕對(duì)定位方式;
關(guān)鍵問(wèn)題:由于每張圖片的寬高不一樣,而瀑布流中要求所有圖片的寬度一致,高度隨寬度等比縮放。而且由于圖片的加載是異步延遲。在不知道圖片高度的情況下,每個(gè)圖片所在的item盒子不好絕對(duì)定位。因此在渲染頁(yè)面前先獲取所有圖片的高度,是解決問(wèn)題的關(guān)鍵點(diǎn)!這里選擇用JS中的Image類,通過(guò)預(yù)加載圖片的方式提前獲取圖片寬高,另外通過(guò)一個(gè)臨時(shí)變量來(lái)計(jì)算是否所有圖片的高度已經(jīng)得到。當(dāng)所有的圖片高度獲取后,開(kāi)始渲染頁(yè)面。
頁(yè)面渲染后,獲取所有圖片所在的盒子,循環(huán)計(jì)算盒子的高度,開(kāi)始設(shè)置每個(gè)盒子item的絕對(duì)定位。
頁(yè)面渲染時(shí),會(huì)出現(xiàn)閃爍的現(xiàn)象。如何解決這個(gè)問(wèn)題呢?這里用了一個(gè)動(dòng)畫(huà)樣式。不過(guò)在第一次加載的時(shí)候,還是會(huì)有一點(diǎn)閃爍的感覺(jué)。
然后就是下拉刷新和上拉加載更多的效果,這里用了有贊的vant組件PullRefresh和List這套組合組件來(lái)實(shí)現(xiàn)。
先看個(gè)效果動(dòng)圖:

靜態(tài)截圖:

二、具體實(shí)現(xiàn)步驟
2.1、頁(yè)面結(jié)構(gòu)設(shè)計(jì),測(cè)試數(shù)據(jù)準(zhǔn)備。
本地準(zhǔn)備一個(gè)json文件數(shù)據(jù),放在項(xiàng)目public文件夾下。注意,本地測(cè)試數(shù)據(jù)必須放在public文件夾下,網(wǎng)絡(luò)請(qǐng)求時(shí)才能請(qǐng)求到數(shù)據(jù),這是vue3.x。新增加一個(gè)axios依賴包,用來(lái)進(jìn)行網(wǎng)絡(luò)請(qǐng)求。部分截圖,及關(guān)鍵代碼:

//數(shù)據(jù)請(qǐng)求
getDataList(){
this.$axios.get("/json/dataList.json").then((res)=>{
let list = res.data.data ? res.data.data: [];
if (list.length > 0){
//從list中取pageSize條數(shù)據(jù)出來(lái)
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); //模擬預(yù)加載圖片,獲取圖片高度
}
else {
this.loadImagesHeight(list);
}
}).catch((res)=>{
console.log("..fail: ", res);
this.$toast.clear();
this.isLoading = false; //下拉刷新請(qǐng)求完成
this.loading = false; //上拉加載更多請(qǐng)求完成
})
},
2.2、預(yù)加載圖片,存儲(chǔ)圖片高度
獲取數(shù)據(jù)后,遍歷數(shù)據(jù)數(shù)組,預(yù)加載圖片,計(jì)算圖片縮放后的高度,存儲(chǔ)起來(lái)。同時(shí)由于圖片加載是異步加載,所以用變量計(jì)數(shù),當(dāng)最后一個(gè)圖片加載完成后,開(kāi)始渲染頁(yè)面。
loadImagesHeight(list){
var count = 0; //用來(lái)計(jì)數(shù),表示是否所有圖片高度已經(jīng)獲取
list.forEach((item, index)=>{
//創(chuàng)建圖片對(duì)象,加載圖片,計(jì)算圖片高度
var img = new Image();
img.src = item.cover;
img.onload = img.onerror = (e)=>{
count++;
if (e.type == 'load'){ //圖片加載成功
//計(jì)算圖片縮放后的高度:圖片原高度/原寬度 = 縮放后高度/縮放后寬度
list[index].imgHeight = Math.round(img.height * this.boxWidth / img.width);
// console.log('index: ', index, ', load suc, imgHeiht: ', list[index].imgHeight);
}
else{ //圖片加載失敗,給一個(gè)默認(rèn)高度50
list[index].imgHeight = 50;
console.log("index: ", index, ", 加載報(bào)錯(cuò):", e);
}
//加載完成最后一個(gè)圖片高度,開(kāi)始下一步數(shù)據(jù)處理
if (count == list.length){
this.resolveDataList(list);
}
}
})
},
2.3、渲染頁(yè)面,設(shè)置絕對(duì)定位
所有圖片通過(guò)預(yù)加載獲取圖片高度后,開(kāi)始渲染頁(yè)面。然后遍歷所有圖片所在盒子標(biāo)簽,獲取盒子高度,設(shè)置每個(gè)盒子的絕對(duì)定位。
resolveDataList(list){ //處理數(shù)據(jù)
//下拉刷新,清空原數(shù)據(jù)
if (this.pageIndex <= 1){
this.itemCount = 0;
this.dataList = [];
this.lastRowHeights = [0, 0]; //存儲(chǔ)每列的最后一行高度清0
}
if (list.length >= this.pageSize){
this.pageIndex++; //還有下一頁(yè)
}
else{
this.finished = true; //當(dāng)前tab類型下所有數(shù)據(jù)已經(jīng)加載完成
}
//合并新老兩個(gè)數(shù)組數(shù)據(jù)
this.dataList = [...this.dataList, ...list];
//判斷頁(yè)面是否有數(shù)據(jù)
this.haveData = this.dataList.length > 0 ? 2 : 1;
this.isLoading = false; //下拉刷新請(qǐng)求完成
this.loading = false; //上拉加載更多請(qǐng)求完成
console.log("...datalist: ", this.dataList);
console.log("...this.isLoading: ", this.isLoading)
this.$nextTick(()=>{
setTimeout(()=>{
//渲染完成,計(jì)算每個(gè)item寬高,設(shè)置標(biāo)簽坐標(biāo)定位
this.setItemElementPosition();
this.isLoading = false; //下拉刷新請(qǐng)求完成
this.loading = false; //上拉加載更多請(qǐng)求完成
}, 1000)
});
},
//獲取每個(gè)item標(biāo)簽高度,設(shè)置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];
//上一個(gè)標(biāo)簽最小高度的列索引
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;
//修改父級(jí)標(biāo)簽的高度
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、其他說(shuō)明
其他頁(yè)面中如下拉刷新,和上拉加載更多等功能,使用了有贊的組件庫(kù)中的PullRefresh 和 List這一套組合組件。感覺(jué)效果挺棒的,使用步驟也簡(jiǎn)單。另外就是在頁(yè)面渲染時(shí),會(huì)出現(xiàn)頁(yè)面閃爍的現(xiàn)象,后面使用了一個(gè)css動(dòng)畫(huà)處理了這個(gè)現(xiàn)象,效果好了很多。但是在第一次加載的時(shí)候,還是有輕微的閃爍現(xiàn)象。等后面找到更好的方法,再更新。
完整效果DEMO地址:https://github.com/xiaotanit/tan_vue/blob/master/src/views/PageWaterFall.vue
總結(jié)
以上所述是小編給大家介紹的vue實(shí)現(xiàn)網(wǎng)絡(luò)圖片瀑布流 + 下拉刷新 + 上拉加載更多(步驟詳解),希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
如果你覺(jué)得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!
相關(guān)文章
Vue后臺(tái)實(shí)現(xiàn)點(diǎn)擊圖片放大功能的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用Vue實(shí)現(xiàn)點(diǎn)擊圖片放大功能,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以參考一下2022-12-12
Vue.js使用v-show和v-if的注意事項(xiàng)
這篇文章一開(kāi)始先對(duì)Vue.js中v-show和v-if兩者的區(qū)別進(jìn)行了簡(jiǎn)單的介紹,而后通過(guò)圖文詳細(xì)給大家介紹了Vue.js使用v-show和v-if注意的事項(xiàng),有需要的朋友們可以參考借鑒,下面來(lái)一起看看吧。2016-12-12
vue路由傳參刷新后數(shù)據(jù)丟失問(wèn)題及解決
這篇文章主要介紹了vue路由傳參刷新后數(shù)據(jù)丟失問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03
關(guān)于在Vue中import和require的用法分析
在Vue項(xiàng)目中,我們經(jīng)常需要引入外部的模塊或文件,這時(shí)候就會(huì)用到import和require這兩個(gè)關(guān)鍵字,本文將詳細(xì)分析它們的用法,并提供具體的代碼實(shí)例和解釋,需要的朋友可以參考下2023-06-06
jenkins自動(dòng)構(gòu)建發(fā)布vue項(xiàng)目的方法步驟
這篇文章主要介紹了jenkins自動(dòng)構(gòu)建發(fā)布vue項(xiàng)目的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01
vue中如何動(dòng)態(tài)綁定圖片,vue中通過(guò)data返回圖片路徑的方法
下面小編就為大家分享一篇vue中如何動(dòng)態(tài)綁定圖片,vue中通過(guò)data返回圖片路徑的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-02-02

