摘要:完整代碼請(qǐng)戳我們回到小程序,此時(shí)接口返回的數(shù)據(jù)如下可以看到每個(gè)圖片都有高度了,接下來我們實(shí)現(xiàn)瀑布流布局,等下,我們搞下瀑布流布局的懶加載,關(guān)于小程序的懶加載,猛戳了解更多。
效果圖
來來來,看啊看,外面的世界多好看,
效果圖展示的是瀑布流布局 && 懶加載的效果
數(shù)據(jù)圖片數(shù)據(jù)來源張鑫旭的網(wǎng)絡(luò)日志
先說下我們的圖片鏈接格式
所有的鏈接都是http://cued.xunlei.com/demos/publ/img/P_${name}.jpg這樣的格式,我們需要改變name的值就行了,當(dāng)name值小于10的時(shí)候,格式是00x,如002、003,大于10的時(shí)候就是023這種。
定義瀑布流布局是一種比較流行的頁面布局方式, 最早采用此布局的網(wǎng)站是Pinterest, 圖片寬度是固定的,高度自動(dòng),產(chǎn)生一種參差不齊的美感。
原理原理很簡單,主要分為以下幾步
1、定義高度數(shù)組和列數(shù)
2、遍歷元素,個(gè)數(shù)小于列數(shù)的直接push到數(shù)組中
3、大于列數(shù)的,獲取高度數(shù)組中最小的值,定義元素的top和left值
4、重要一點(diǎn) 更新高度數(shù)組,將最小高度加上當(dāng)前元素的高度
知道原理了,代碼應(yīng)該怎么寫呢?這里用web端來示例,大概如下
let heightArr = [] let col = 2 let allBox = document.querySelectorAll(".box") // 獲取所有盒子 for(let i in allBox){ let boxWidth = allBox[0].offsetWidth // 獲取盒子寬度 都一樣直接取第一個(gè) let boxHeight = allBox[i].offsetHeight if(i < col){ heightArr.push(boxHeight) // 把第一行高度都添加進(jìn)去 } else { // 進(jìn)行布局操作 let minHeight = Mac.min.apply(null, heightArr) // 獲取最小高度 let minIndex = getIndex(heightArr, minHeight) // 獲取最小高度的下標(biāo) 要不就是0 要不就是1 allBox[i].style.position = "absolute" allBox[i].style.top = minHeight + "px" allBox[i].style.width = minIndex * boxWidth + "px" heightArr[minIndex] += boxHeight // 更新最新高度 } } // 獲取下標(biāo) getIndex(arr, val){ for(i in arr){ if(arr[i] == val) { return i } } }
上面就是實(shí)現(xiàn)瀑布流的主要邏輯,這里大概寫了下,接下來我們看看小程序怎么實(shí)現(xiàn)。
實(shí)現(xiàn)在web頁面里面我們可以直接獲取、操作DOM,實(shí)現(xiàn)起來很方便,何況還有很多的jquery插件可以使用。我們知道小程序里面是沒有DOM的,那應(yīng)該怎么實(shí)現(xiàn)呢?我們把思路轉(zhuǎn)換下就行了。
這里我們用三種方式來實(shí)現(xiàn)瀑布流布局。
CSS使用css3來實(shí)現(xiàn)是最簡單的,我們先撿簡單的來說,
使用column-count屬性設(shè)置列數(shù)
使用wx-if進(jìn)行判斷將圖片渲染到左側(cè)還是右側(cè)
wxmlwxss
.container{ column-count: 2; /*設(shè)置列數(shù)*/ column-gap:2rpx; padding-left: 8rpx; } image{ width: 182px; box-shadow: 2px 2px 4px rgba(0,0,0,.4); }
js獲取下數(shù)據(jù)即可,這里就不贅述了。
節(jié)點(diǎn)信息小程序可以通過WXML節(jié)點(diǎn)信息API來獲取元素的信息,接下來我們來擼碼。
wxmlwxss
.container{ position: relative; display: flow-root; } .box{ float: left; display: flex; margin-left:5rpx; box-shadow: 2rpx 2rpx 5rpx rgba(0,0,0,.3); border: 1rpx solid #ccc; box-sizing: border-box; padding: 10px; } .box:nth-child(2){ margin-left: 12rpx; } image{ width: 100%; }js
圖片鏈接為http://cued.xunlei.com/demos/publ/img/P_${name}.jpg, 只需要更改name就行了
首先處理我們的數(shù)據(jù)
// 創(chuàng)建長度為30的數(shù)組 const mockData = () => { return Array.from(Array(30).keys()).map(item => { if (item < 10) { return "00" + item } else { return "0" + item } }) } // 擴(kuò)展成我們需要的數(shù)據(jù) const createGroup = () => { let group = [] let list = mockData() list.forEach(item => { group.push({ name: item, position: "static", top: "", left: "" }) }) return group }
然后進(jìn)行瀑布流布局,主要代碼如下
load(e){ // 監(jiān)聽圖片加載完 獲取圖片的高度 this.setData({ height: [...this.data.height, e.detail.height] }) this.showImg() // 調(diào)用渲染函數(shù) }, showImg(){ let height = this.data.height if (height.lenth != this.data.group .legth){ // 保證所有圖片加載完 return } setTimeout(()=>{ // 異步執(zhí)行 wx.createSelectorQuery().selectAll(".box").boundingClientRect((ret) => { let cols = 2 var group = this.data.group var heightArr = []; for (var i = 0; i < ret.length; i++) { var boxHeight = height[i] if (i < cols) { heightArr.push(boxHeight + 25) } else { var minBoxHeight = Math.min.apply(null, heightArr); var minBoxIndex = getMinBoxIndex(minBoxHeight, heightArr); group[i].position = "absolute" group[i].top = `${minBoxHeight}px` group[i].left = minBoxIndex * this.data.width / 2 + "px" group[i].left = minBoxIndex == 0 ? minBoxIndex * this.data.width / 2 + "px" : minBoxIndex * this.data.width / 2 + 5 + "px" heightArr[minBoxIndex] += (boxHeight + 25) } } this.setData({ group }) wx.hideLoading() }).exec() }, 200) }
可以看到實(shí)現(xiàn)的邏輯和上面的大概類似,只不過這里我們修改的是數(shù)據(jù),畢竟小程序是數(shù)據(jù)驅(qū)動(dòng)的嘛。
這里主要我們監(jiān)聽image組件的bindload事件來獲取每張圖片的高度,獲取了高度才能進(jìn)行布局,大部分的時(shí)間也都用來加載圖片了,能不能優(yōu)化呢?當(dāng)然可以了,我們使用node把數(shù)據(jù)包裝下。
后端處理數(shù)據(jù)上面我們說到在小程序內(nèi)部獲取圖片的高度是個(gè)費(fèi)力不討好的事,我們使用node來獲取圖片高度,然后包裝下再給小程序使用。
使用request進(jìn)行請(qǐng)求
使用image-size獲取圖片的高度
最后將獲取后將數(shù)據(jù)寫入文件,啟動(dòng)一個(gè)服務(wù)提供接口
這里主要說下碰到的問題
1、request模塊的請(qǐng)求默認(rèn)返回來的是個(gè)String類型的字符串,使用image-size模塊傳入的必須是Buffer,怎么破呢?在request請(qǐng)求中設(shè)置encoding為null即可
2、我們這里爬取了100張圖片,怎么保證都已經(jīng)爬取完了呢?可以這樣寫
Promise.all(List.map(item => getImgData(item))) // getImgData函數(shù)是獲取圖片的函數(shù) 會(huì)返回個(gè)promise
3、如果請(qǐng)求了幾次,發(fā)現(xiàn)有的圖片獲取不到了,報(bào)錯(cuò)了,怎么回事呢,人家畢竟做了防爬的,恭喜你中獎(jiǎng)了,換個(gè)ip再試吧(可以把代碼放在服務(wù)器上面,或者換個(gè)Wi-Fi),其實(shí)我們只需要爬一次就行,生成完文件還爬干嘛啊。
完整代碼請(qǐng)戳github
我們回到小程序,此時(shí)接口返回的數(shù)據(jù)如下
可以看到每個(gè)圖片都有高度了,接下來我們實(shí)現(xiàn)瀑布流布局,等下,我們搞下瀑布流布局的懶加載,關(guān)于小程序的懶加載,猛戳了解更多。
怎么實(shí)現(xiàn)呢?主要分為兩步
1、將元素瀑布流布局
2、創(chuàng)建IntersectionObserver,進(jìn)行懶加載
先開始我們的布局吧
wxml上面我們使用wx-if通過show這個(gè)字段來進(jìn)行判斷了圖片是否加載,
使用一個(gè)view組件用來占位,然后更改show字段就可以顯示圖片了
js我們使用兩個(gè)for循環(huán),先來進(jìn)行布局
let cols = 2 let list = this.data.list let heightArr = []; for(let i in list){ var boxHeight = list[i].height if (i < cols) { heightArr.push(boxHeight + 5) } else { var minBoxHeight = Math.min.apply(null, heightArr); var minBoxIndex = getMinBoxIndex(minBoxHeight, heightArr); list[i].position = "absolute" list[i].top = `${minBoxHeight}px` list[i].left = minBoxIndex * 182 + "px" list[i].left = minBoxIndex == 0 ? minBoxIndex * 182 + "px" : minBoxIndex * 182 + 4 + "px" heightArr[minBoxIndex] += (boxHeight + 5) } } this.setData({ list })
布局完后,創(chuàng)建IntersectionObserver,動(dòng)態(tài)判斷image節(jié)點(diǎn)的顯示
for (let i in list) { wx.createIntersectionObserver().relativeToViewport({ bottom: 20 }).observe(".pic-" + i, (ret) => { if (ret.intersectionRatio > 0) { list[i].show = true } this.setData({ list }) }) }最后
我們使用三種方式完成了小程序的瀑布流布局,還額外完成了基于瀑布流的懶加載。可以發(fā)現(xiàn)使用css最簡便,雖然小程序不能操作DOM,但是我們改完數(shù)據(jù)其實(shí)和改變DOM一樣,將觀念轉(zhuǎn)變過來,小程序的開發(fā)還是很爽的。
最后的最后,各位,周末快樂。
github
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/95026.html
摘要:瀑布流布局中的圖片有一個(gè)核心特點(diǎn)等寬不定等高,瀑布流布局在國內(nèi)網(wǎng)網(wǎng)站都有一定規(guī)模的使用,比如花瓣網(wǎng)等等。那么接下來就基于這個(gè)特點(diǎn)開始瀑布流探索之旅。 showImg(https://segmentfault.com/img/remote/1460000013059759?w=640&h=280); 瀑布流布局中的圖片有一個(gè)核心特點(diǎn) —— 等寬不定等高,瀑布流布局在國內(nèi)網(wǎng)網(wǎng)站都有一定規(guī)模...
摘要:瀑布流布局中的圖片有一個(gè)核心特點(diǎn)等寬不定等高,瀑布流布局在國內(nèi)網(wǎng)網(wǎng)站都有一定規(guī)模的使用,比如花瓣網(wǎng)等等。那么接下來就基于這個(gè)特點(diǎn)開始瀑布流探索之旅。 showImg(https://segmentfault.com/img/remote/1460000013059759?w=640&h=280); 瀑布流布局中的圖片有一個(gè)核心特點(diǎn) —— 等寬不定等高,瀑布流布局在國內(nèi)網(wǎng)網(wǎng)站都有一定規(guī)模...
摘要:瀑布流布局中的圖片有一個(gè)核心特點(diǎn)等寬不定等高,瀑布流布局在國內(nèi)網(wǎng)網(wǎng)站都有一定規(guī)模的使用,比如花瓣網(wǎng)等等。那么接下來就基于這個(gè)特點(diǎn)開始瀑布流探索之旅。 showImg(https://segmentfault.com/img/remote/1460000013059759?w=640&h=280); 瀑布流布局中的圖片有一個(gè)核心特點(diǎn) —— 等寬不定等高,瀑布流布局在國內(nèi)網(wǎng)網(wǎng)站都有一定規(guī)模...
摘要:參考小紅書的瀑布流效果,小紅書是分左右兩欄的,按照奇數(shù)偶數(shù)來顯示就可以。但是問題來了,隨著每個(gè)元素高度的不確定性,很大幾率會(huì)出現(xiàn)左右兩欄高度相差大的問題。 想要實(shí)現(xiàn)瀑布流的布局效果,并且是按照從左到右順序顯示的話,css布局方式暫時(shí)還不能滿足我們的需求。參考小紅書的瀑布流效果,小紅書是分左右兩欄的,按照奇數(shù)偶數(shù)來顯示就可以。 ...
閱讀 3834·2021-09-27 13:56
閱讀 880·2021-09-08 09:36
閱讀 765·2019-08-30 15:54
閱讀 609·2019-08-29 17:29
閱讀 927·2019-08-29 17:21
閱讀 1682·2019-08-29 16:59
閱讀 2757·2019-08-29 13:03
閱讀 2964·2019-08-29 12:47