在微信小程式中,我們使用Image
元件來展示圖片,圖片源可以是本地資源,也可以是伺服器資源。但是為了內容的動態展示,我們絕大多數情況下,會使用伺服器資源來展現作為image
的圖片源。既然是伺服器資源,那麼就需要依賴於網路的快慢,如果在網路慢的情況下,image
載入圖片的過程可能會非常慢,所以在載入圖片的過程中,如果不做處理,會出現一片空白的情況,直到圖片載入完成,這是非常差的使用者體驗。
為了提高使用者體驗度,我們可以在圖片載入完成之前,預先展示一張本地的預設佔點陣圖片,而不是顯示空白。
小程式的image
元件沒有提供預設圖片的屬性,需要我們自己實現這個功能。
實現原理
微信小程式的image
元件有兩個屬性:
屬性名 | 型別 | 說明 |
---|---|---|
binderror | HandleEvent | 當錯誤發生時,釋出到 AppService 的事件名,事件物件event.detail = {errMsg: 'something wrong'} |
bindload | HandleEvent | 當圖片載入完畢時,釋出到 AppService 的事件名,事件物件event.detail = {height:'圖片高度px', width:'圖片寬度px'} |
我們可以實現這兩個事件:
- 實現
bindload
,在圖片未載入完成時,顯示佔點陣圖,一旦載入完成,馬上隱藏佔點陣圖,顯示真正的業務圖片 - 實現
binderror
,在圖片載入錯誤時,顯示佔點陣圖。
具體實現
新建一個小程式專案
開啟微信開發者工具,新建一個小程式專案Demo
,刪除無用程式碼
自定義元件
在實際開發中,在多個地方都會用到image
元件,如果在每個使用的地方都去實現一遍佔點陣圖的功能,不僅會增加程式碼量,而且也增加維護量,所以,我們可以把這些邏輯,封裝為一個自定義元件,這裡我們取名為image-loader
,然後任何用到的地方,直接用image-loader
去代替image
就可以了。
新建image-loader
使用微信開發工具新建一個自定義元件,並位於專案的目錄components
中,這個大家使用過微信開發工具的肯定都會操作,這裡就不在贅述。然後找到一張佔點陣圖,放到專案的images
目錄下,完成之後
現在專案的目錄結構:
$ tree
.
├── app.js
├── app.json
├── app.wxss
├── components
│ ├── image-loader.js
│ ├── image-loader.json
│ ├── image-loader.wxml
│ └── image-loader.wxss
├── images
│ └── placeholder800x400.png
├── pages
│ └── index
│ ├── index.js
│ ├── index.json
│ ├── index.wxml
│ └── index.wxss
└── project.config.json
複製程式碼
實現image-loader
我們在image-loader
中,加入兩個image
,一個image
用於載入預設圖片,一個image
用於載入真正的圖片。為了描述方便,我們把這兩個image
稱為image-default
和image-real
在初始化的時候,我們顯示的是image-default
圖片,同時,image-real
也會一起載入,只不過,會通過css
屬性控制image-real
不顯示:
.before-load {
width: 0;
height: 0;
opacity: 0;
}
複製程式碼
然後給image-real
實現bindload
和binderror
,在載入完成併成功後,把image-default
的width
和height
都置為空,這樣image-default
就不會再顯示,同時讓image-real
的widhth
和height
恢復原始值,並把opcity
置為1
。
下面貼出所有程式碼
image-loader.js
/**
* 圖片預載入元件
*/
Component({
properties: {
//預設圖片
defaultImage: String,
//原始圖片
originalImage: String,
width: String,
height: String,
//圖片剪裁mode,同Image元件的mode
mode: String
},
data: {
finishLoadFlag: false
},
methods: {
finishLoad: function (e) {
this.setData({
finishLoadFlag: true
})
}
}
})
複製程式碼
image-loader.jsong
{
"component": true,
"usingComponents": {}
}
複製程式碼
image-loader.wxml
<image wx:if='{{!finishLoadFlag}}' mode='{{mode}}' src='{{defaultImage}}' style='{{width ? "width:" + width : ""}};{{height ? "height:" + height : ""}}' />
<image mode='{{mode}}' class='{{finishLoadFlag ? "" : "before-load"}}' src='{{originalImage}}' bindload='finishLoad' style='{{finishLoadFlag && width ? "width:" + width : ""}};{{finishLoadFlag && height ? "height:" + height : ""}}' />
複製程式碼
image-loader.wxss
.before-load {
width: 0;
height: 0;
opacity: 0;
}
複製程式碼
注意:我這裡為了簡化,只實現了
image
的bindload
而未實現binderror
。
測試
最後,我們修改pages/index
頁面程式碼測試一下
- 啟用外掛
index.json
{
"usingComponents": {
"image-loader": "/components/image-loader"
}
}
複製程式碼
- 測試程式碼:
index.wxml
<image-loader default-image='../images/placeholder800x400.png' mode='widthFix' original-image='https://www.neware.shop/demo/mobile/api/v1/public/image/download/201809051000165950' width="400rpx" height="200rpx" />
複製程式碼
原始碼
完整的元件原始碼我放在了 Github
上,大家可以去檢視:wx-mini-image-preload