首先了解下什麼是骨架屏?
骨架屏就是在頁面資料尚未加載前先給使用者展示出頁面的大緻結構,直到請求資料傳回後再渲染頁面,補充進需要顯示的資料内容。常用于文章清單、動态清單頁等相對比較規則的清單頁面。 很多項目中都有應用餓了麼h5版本,知乎,facebook等網站中都有應用。
以下圖舉例,常用餓了麼的童鞋,應該看到過餓了麼的這個首頁預加載圖的效果:
餓了麼h5實作方案
咱們來聊聊小程式的實作方案:
1.最簡單最快捷最暴力的,直接讓設計一張圖檔蓋上去,當loading使用。
舉例:餓了麼的訂單頁面,檢視了下源碼,是使用的SVG的圖
2.前端使用view寫死一套資料(缺點很明顯,假如頁面布局有修改的話,那麼除了修改業務代碼之外還需要額外修改骨架屏,增加了維護的成本)
舉例:簡單寫了個微信小程式的代碼片段(支付寶暫無代碼片段功能):
https://developers.weixin.qq.com/s/ZAuYzHmX7ObC3.頁面Data裡寫死一套預設資料,使用小程式的
my.createSelectorQuery().selectAll選擇了所有要渲染的矩形和圓形節點,在頁面中,使用循環,周遊出所有的節點,再加上樣式。
基本原理就是
- 在元件初始化時,設定其絕對定位,大小為整個螢幕大小
- 然後用節點查詢方法,找到類名等于skeletons的元素,并設定元件的背景的位置及大小和元素的一緻,覆寫這個元素。
- 用節點查詢方法,找到所有的類名等于skeletons-circle 元素,并将它們的位置及大小資訊加入到skeletons-circle-Arr數組中,在axml中用a:for循環渲染出來(也是絕對定位)
- 用節點查詢方法,找到所有的類名等于skeletons-rect 元素,并将它們的位置及大小資訊加入到skeletons-rect-Arr數組中,在axml中用a:for循環渲染出來(也是絕對定位)
當然啦,這裡還有一些判斷,還可以設定螢幕上提示是旋轉小圈圈還是背景色漸變提醒等,都是一些比較細節的東西,就不細說。
那麼到這就完了嗎?當然木有,現在說下最後一種方案(目前我們小程式正在使用的方案)。
4. 如何更好的把骨架屏代碼嵌入到業務裡面,是否可以在接口請求成功後,先渲染出一套接口傳回的資料比對的骨架,再展示給使用者看呢,減少使用者檢視白屏(loading)時間。(缺點是如果請求挂掉,骨架屏是不會渲染出來的)
這是我們線上版本效果示例圖:
首先來看 如何操作:
使用
my.createSelectorQuery擷取到相關節點進行渲染操作,但是我們把預設資料這一欄更改為動态資料。
核心代碼就是自定義元件内抛出的isNodes和isComplete屬性
//axml
<skeletons isNodes="{{isNodes}}" isComplete="{{isComplete}}"" />
//頁面節點上需要手動添加一個樣式類。
比如輪播圖 寬686rpx,高140rox,是長方形那麼給他的樣式上加上‘skeletions-rect’,如果是圓形給他加上‘skeletons-circle’
業務内代碼如下:
<!-- 輪播圖元件 -->
<block a:if="{{swiperData.length > 0}}">
<swiper class="swiperSlide" indicator-dots="{{indicatorDots}}" indicator-color="#ccc" indicator-active-color="#00CC88" autoplay circular>
<block a:for="{{swiperData}}" a:key="{{index}}">
<swiper-item>
<view class="swiper-item">
<image lazy-load src="{{item.image}}" data-index="{{index}}" onTap="universalJump" class="skeletons-rect" />
</view>
</swiper-item>
</block>
</swiper>
<!-- <qts-swiper resourseFrom="{{swiperData}}" indicatorDots="{{indicatorDots}}"></qts-swiper> -->
</block>
相關JS如下:
initData() {
let postData = {
townId: util.getStorageSync('townId') || 87
}
// 初始化請求第一個接口
app.postAjax('https://url.com', postData).then((res) => {
if (res.success) {
this.setData({
bodyData: res.data, //頁面展示資料的大對象
isNodes: true //抓取節點繪制骨架屏
}, () => {
this.setData({
isComplete: true //節點繪制完成,隐藏骨架屏
})
})
} else {
util.toast(res.msg || '團團開小差啦,請稍後重試')
}
}, () => {
util.toast('團團開小差啦,請稍後重試')
})
},
在微信端的難題:元件之間無法樣式穿透的問題(A元件通過index頁面影響B元件的樣式),在支付寶端完美不存在,算是解決了一個大問題吧。
最後完整元件代碼位址:
https://gitee.com/minchangyong/skeletons