一開始覺得這個問題很簡單,每插入一張圖片之前比較各個“流”的高度,找個最短的放進去就行了。後來發現沒那麼簡單。 直接想到的問題就是圖片未載入完成是得不到圖片的完整高度的,後來找到dom的naturalHeight屬性,可以在圖片未載入成功時就獲取到圖片高度
然後開始常規操作,用nextTick遞迴把圖片資料插入到對應的陣列中,但是nextTick中獲取圖片dom的naturalHeight是獲取不到的,但是頁面中圖片就算未載入完成是可以獲取到的。猜想是vue渲染完圖片的dom時執行nextTick,圖片剛開始載入,這時候介面還沒有獲取到計算naturalHeight屬性相關的資料。所以這條路就是走死了,因為這個方法下圖片什麼時候載入完成無法監控,都是第一張圖片插入之後第二張圖片放哪裡沒法計算。
第一時間想到的就是setInterval,然後不到一秒鐘就被自己否決了,醜而且耗費效能,寧願在資料庫裡擴充套件width、height欄位也不用這個方法(我還真的擴充套件了)。但是不太服氣,然後尋找滿是廣告的度娘,發現一個方法,既然之前問題出在圖片什麼時候載入完成無法監控,那就用image.onload()方法獲取圖片資訊,然後在回撥裡面丁零當啷一頓操作拼好dom,插入到頁面中。 偷來的程式碼
sort(j) {
if (j < this.moments.length) {
let that = this;
// 建立Image類
var newImg = new Image();
// 獲取要載入的圖片地址
newImg.src =
"http://lanyue.ink:8123/images/" +
(Math.floor(Math.random() * 15) + 1) +
".png";
// 圖片載入完成後(非同步)
newImg.onload = () => {
// 四個管道的高度
var arr = [
that.$refs.piping0.offsetHeight,
that.$refs.piping1.offsetHeight,
that.$refs.piping2.offsetHeight,
that.$refs.piping3.offsetHeight
];
//獲取管道最小高度
var min = arr.indexOf(Math.min.apply(Math, arr));
// 新增卡片的模板
var html =
`<div class="card">
<img src=` + newImg.src + `>
<div>
<img src="http://lanyue.ink:8123/images/avatar.jpg" alt="">
<div>` + this.moments[j].id + " " + this.moments[j].content + `</div>
</div>
</div>`;
//給最小的管道新增卡片
if (min == 0) {
that.$refs.piping0.innerHTML += html;
} else if (min == 1) {
that.$refs.piping1.innerHTML += html;
} else if (min == 2) {
that.$refs.piping2.innerHTML += html;
} else if (min == 3) {
that.$refs.piping3.innerHTML += html;
}
that.sort(j + 1);
};
}
},
複製程式碼
作者如果看到了不要噴我,都走到這一步了,為什麼還要用插入html的方式,拿到圖片的寬高,加一個計算“流”高度的欄位,插入一張圖就加一個圖片的高度,這樣也就不用再從dom中獲取“流”的高度。這樣的好處有兩個,一是減少一次dom的查詢,二是如果頁面需要響應式,插入html的方式其實是無法通過直接改變資料操作dom,違背了vue的本意(對於兩個方法的效能消耗有機會多做研究,感覺起來應該是我的方法美一點)。
getImageList() {
let that = this;
imageService.getImageList(this, {
params: {
categoryId: 37
}
}).then(function (result) {
if (result.code === 0) {
that.tempImage = result.data;
that.pushImage(0);
}
});
},
pushImage(index) {
if (index >= this.tempImage.length) return;
let img = new Image(), that = this;
img.src = that.$store.state.imageURL + that.tempImage[index].url;
img.onload = () => {
let min = that.imageHeight[0], imageIndex = 0;
that.imageHeight.forEach(function (item, _index) {
if (min > item) {
min = item;
imageIndex = _index;
}
});
that.imageHeight[imageIndex] += img.naturalHeight / img.naturalWidth;
that.imageList[imageIndex].push(that.tempImage[index]);
that.pushImage(index + 1);
}
},
複製程式碼
最後再加上一段監控頁面位置函式,實現拉到底部載入圖片的功能
pullDown() {
// 獲取滾輪位置
this.height1 = window.pageYOffset ||
document.documentElement.scrollTop ||
document.body.scrollTop;
// 文件高度
this.height2 = document.body.scrollHeight;
// 可視區域
// 設定compatMode相容IE
this.height3 = document.compatMode === "CSS1Compat"
? document.documentElement.clientHeight
: document.body.clientHeight;
// 如果滾動到最低(這裡設定離最底還有100距離才觸發函式)
// available條件是為了防止觸底時一直不斷地請求。因此,請求一次後available設為0,直到滾動到離底部超過100距離(即資料載入玩後)才設為1
if (this.height3 + this.height1 >= this.height2 - 100 && this.available) {
this.available = false;
//請求下一頁,如果當前頁等於最大頁,直接返回
if (this.pagination.currentPage >= this.pagination.totalPage) {
this.footerVisible = true;
return;
}
this.pagination.currentPage++;
this.getImagePage();
} else if (this.height3 + this.height1 < this.height2 - 100) {
this.available = true;
}
}
複製程式碼
最終效果圖
參考文章:來自MarieDreamer blog.csdn.net/qq_33514421…