微信小程式image載入成功前顯示預設佔點陣圖

Quenice發表於2018-09-28

在微信小程式中,我們使用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-defaultimage-real

在初始化的時候,我們顯示的是image-default圖片,同時,image-real也會一起載入,只不過,會通過css屬性控制image-real不顯示:

.before-load {
  width: 0;
  height: 0;
  opacity: 0;
}
複製程式碼

然後給image-real實現bindloadbinderror,在載入完成併成功後,把image-defaultwidthheight都置為空,這樣image-default就不會再顯示,同時讓image-realwidhthheight恢復原始值,並把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;
}
複製程式碼

注意:我這裡為了簡化,只實現了imagebindload而未實現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

相關文章