Vue 原生瀑布流圖片
阿新 • • 發佈:2018-11-12
效果
思路
1、html中建立四個“管道”
2、後臺獲取到資料
3、遍歷資料,獲取高度最小的管道,填入資料
4、滾動條到底時觸發函式,獲取下一頁資料,然後再執行步驟3
參考
程式碼
template:建立四個piping,ref引數是為了在js中獲取dom元素。
<template> <div class="friend_moments"> <div class="water"> <div class="piping" ref="piping0"> </div> <div class="piping" ref="piping1"> </div> <div class="piping" ref="piping2"> </div> <div class="piping" ref="piping3"> </div> </div> </div> </template>
script:
export default { data() { return { moments: [], available: 1, height1: 0, height2: 0, height3: 0, page: 1 }; }, created() { // 獲取第一頁資料 this.fetchMoments(); }, mounted() { // 用來監聽滾輪 window.addEventListener("scroll", this.handleScroll); }, methods: { fetchMoments() { // 請求介面方法 fetch("api/moments") .then(res => res.json()) .then(res => { this.moments = res.data; // 分配資料到指定管道 this.sort(0); }); }, // sort()函式是遞迴的,因為要確保每個卡片的圖片載入完成後再獲取管道的高度,但是圖片載入完成的函式是個非同步函式, // 如果放在for迴圈中會打亂順序,因此要使非同步函式同步執行,for迴圈改為遞迴。 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); }; } }, handleScroll() { // 獲取滾輪位置 var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop; this.height1 = scrollTop; // 文件高度 this.height2 = document.body.scrollHeight; // 可視區域 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.page++; this.available = 0; let that = this; fetch("api/moments?page=" + this.page) .then(res => res.json()) .then(res => { that.moments = res.data; if (that.moments[0]) { that.sort(0); } else { that.page--; } }); } else if (this.height3 + this.height1 < this.height2 - 100) { this.available = 1; } } } };
scss:
<style lang="scss"> .friend_moments { width: 100%; display: flex; justify-content: center; } .a { position: fixed; width: 200px; top: 200px; right: 100px; z-index: 10; background: #eee; } .water { width: 1240px; margin-top: 60px; display: flex; align-items: flex-start; margin-bottom: 100px; .piping { width: 25%; padding: 10px; padding-bottom: 0px; } } .card { width: 290px; border-radius: 5px; box-shadow: 0px 0px 5px #888888; margin-bottom: 20px; > img:first-child { width: 100%; border-radius: 5px; } > div:nth-child(2) { display: flex; align-items: center; padding: 10px; > img { border-radius: 100%; width: 32px; height: 32px; margin-right: 10px; } } } </style>
擴充套件
如果希望圖片框大小一樣,則設定圖片為背景圖片,cover居中顯示。
1、就把scss中的card類改為:
.card {
width: 290px;
border-radius: 5px;
box-shadow: 0px 0px 5px #888888;
margin-bottom: 20px;
> div:first-child {
width: 100%;
height: 200px;
background-repeat: no-repeat;
background-position: center;
background-size: cover;
border-radius: 5px;
}
> div:nth-child(2) {
display: flex;
align-items: center;
padding: 10px;
> img {
border-radius: 100%;
width: 32px;
height: 32px;
margin-right: 10px;
}
}
}
2、把script中html模板改成:
var html =
`<div class="card">
<div style=background-image:url(` + newImg.src + `)></div>
<div>
<img src="http://lanyue.ink:8123/images/avatar.jpg" alt="">
<div>` + this.moments[j].id + " " + this.moments[j].content + `</div>
</div>
</div>`;
修改後的效果:
這樣,高度的差別就主要來自卡片的底部內容高度。