小程式之圖片懶載入[完美方案,你不來看看?]

小心夾手發表於2018-04-27

效果圖

既然來了,把妹子都給你。

小程式之圖片懶載入[完美方案,你不來看看?]

定義

懶載入,前端人都知道的一種效能優化方式,簡單的來說,只有當圖片出現在瀏覽器的可視區域內時,才設定圖片正真的路徑,讓圖片顯示出來。這就是圖片懶載入。

實現原理

監聽頁面的scroll事件,判讀元素距離頁面的top值是否是小於等於頁面的可視高度

判斷邏輯程式碼如下

element.getBoundingClientRect().top <= document.documentElement.clientHeight ? 顯示 : 預設

我們知道小程式頁面的指令碼邏輯是在JsCore中執行,JsCore是一個沒有視窗物件的環境,所以不能在指令碼中使用window,也無法在指令碼中操作元件。

所以關於圖片懶載入就需要在資料上面做文章了。

小程式之圖片懶載入[完美方案,你不來看看?]

頁面

頁面上面只需要根據資料的某一個欄位來判斷是否顯示圖片就可以了,欄位為Boolean型別,當為false的時候顯示預設圖片就行了。

程式碼大概長成這樣

<view wx:for="{{list}}" class='item item-{{index}}'
 wx:key="{{index}}">
	<image class="{{item.show ? 'active': ''}}" src="{{item.show ? item.src : item.def}}"></image>
</view>
複製程式碼

佈局跟簡單,view元件裡面有個圖片,並迴圈list,有多少就展示多少

image元件的src欄位通過每一項的show來進行繫結,active是加了個透明的過渡

樣式

image{
	transition: all .3s ease;
	opacity: 0;
}
.active{
	opacity: 1;
}

複製程式碼

邏輯

本位主要講解懶載入,所以把資料寫死在頁面上了

資料結構如下:

小程式之圖片懶載入[完美方案,你不來看看?]

我們使用兩種方式來實現懶載入,準備好沒有,一起來快樂的擼碼吧。

WXML節點資訊

小程式支援呼叫createSelectQuery建立一個SelectorQuery例項,並使用select方法來選擇節點,並通過boundingClientRect來獲取節點資訊。

wx.createSelectorQuery().select('.item').boundingClientRect((ret)=>{
	console.log(ret)
}).exec()
 
複製程式碼

顯示結果如下

小程式之圖片懶載入[完美方案,你不來看看?]
悄悄告訴你,小程式裡面有個onPageScroll函式,是用來監聽頁面的滾動的。 還有個getSystemInfo函式,可以獲取獲取系統資訊,裡面包含螢幕的高度。

接下來,思路就透徹了吧。還是上面的邏輯, 扒拉扒拉直接寫程式碼就行了,這裡只寫下主要的邏輯,完整程式碼請戳文末github

showImg(){
	let group = this.data.group
	let height = this.data.height  // 頁面的可視高度
	
	wx.createSelectorQuery().selectAll('.item').boundingClientRect((ret) => {
	 ret.forEach((item, index) => {
	   if (item.top <= height) { 判斷是否在顯示範圍內
	     group[index].show = true // 根據下標改變狀態
	   }
	 })
	 this.setData({
	   group
	 })
	}).exec()

}
onPageScroll(){ // 滾動事件
	this.showImg()
}
複製程式碼

至此,我們完成了一個小程式版的圖片懶載入,只是思維轉變了下,其實並沒有改變實現方式。我們來學些新的東西吧。

節點佈局相交狀態

節點相交狀態是啥?它是一個新的API,叫做IntersectionObserver, 本文只講解簡單的使用,瞭解更多請猛戳沒錯,就是點我

小程式裡面給它的定義是節點佈局交叉狀態API可用於監聽兩個或多個元件節點在佈局位置上的相交狀態。這一組API常常可以用於推斷某些節點是否可以被使用者看見、有多大比例可以被使用者看見。

裡面設計的概念主要有五個,分別為

  • 參照節點:以某參照節點的佈局區域作為參照區域,參照節點可以有多個,多個話參照區域取它們的佈局區域的交集
  • 目標節點:監聽的目標,只能是一個節點
  • 相交區域:目標節點與參照節點的相交區域
  • 相交比例:目標節點與參照節點的相交比例
  • 閾值:可以有多個,預設為[0], 可以理解為交叉比例,例如[0.2, 0.5]

關於它的API有五個,依次如下

1、createIntersectionObserver([this], [options]),見名知意,建立一個IntersectionObserver例項

2、intersectionObserver.relativeTo(selector, [margins]), 指定節點作為參照區域,margins引數可以放大縮小參照區域,可以包含top、left、bottom、right四項

3、intersectionObserver.relativeToViewport([margin]),指定頁面顯示區域為參照區域

4、intersectionObserver.observer(targetSelector, callback),引數為指定監聽的節點和一個回撥函式,目標元素的相交狀態發生變化時就會觸發此函式,callback函式包含一個result,下面再講

5、intersectionObserver.disconnect() 停止監聽,回撥函式不會再觸發

然後說下callback函式中的result,它包含的欄位為

欄位名 型別 說明
intersectionRatio Number 相交比例
intersectionRect Object 相交區域的邊界,包含 left 、 right 、 top 、 bottom 四項
boundingClientRect Object 目標節點佈局區域的邊界,包含 left 、 right 、 top 、 bottom 四項
relativeRect Object 參照區域的邊界,包含 left 、 right 、 top 、 bottom 四項
time Number 相交檢測時的時間戳

我們主要使用intersectionRatio進行判斷,當它大於0時說明是相交的也就是可見的。

先來波測試題,請說出下面的函式做了什麼,並且log函式會執行幾次

1、
wx.createIntersectionObserver().relativeToViewport().observer('.box', (result) => {
 	console.log('監聽box元件觸發的函式')   
 })
 
2、
wx.createIntersectionObserver().relativeTo('.box').observer('.item', (result) => {
 	console.log('監聽item元件觸發的函式') 
})

3、
wx.createIntersectionObserver().relativeToViewport().observer('.box', (result) => {
	if(result.intersectionRatio > 0){
		console.log('.box元件是可見的') 
	}
})
複製程式碼

duang,揭曉答案。

第一個以當前頁面的視窗監聽了.box元件,log會觸發兩次,一次是進入頁面一次是離開頁面

第二個以.box節點的佈局區域監聽了.item元件,log會觸發兩次,一次是進入頁面一次是離開頁面

第三個以當前頁面的視窗監聽了.box元件,log只會在節點可見的時候觸發

好了,題也做了,API你也掌握了,相信你已經可以使用IntersectionObserver來實現圖片懶載入了吧,主要邏輯如下

let group = this.data.group // 獲取圖片陣列資料
for (let i in this.data.group){   wx.createIntersectionObserver().relativeToViewport().observe('.item-'+ i, (ret) => {
	   if (ret.intersectionRatio > 0){
	     group[i].show = true 
	   }
	   this.setData({
	     group
	   })
	 })
}
複製程式碼

最後

至此,我們使用兩種方式實現了小程式版本的圖片懶載入,可以發現,使用IntersectionObserver來實現不要太酸爽。

本文程式碼請戳github

相關文章