一般情況下(xia),在首屏數據(ju)未拿到之前,為了提(ti)升用戶(hu)的體驗,會在頁面(mian)上展示一個loading的圖(tu)層,類似下(xia)面(mian)這個
其(qi)中除了(le)菊花圖以外網上還流傳這(zhe)各種(zhong)各樣的loading動(dong)畫(hua),在(zai)PC端(duan)上幾乎要(yao)統一(yi)江湖了(le),不過(guo)最近在(zai)移動(dong)端(duan)上面(mian)看到不同于菊花圖的加載方(fang)式,就(jiu)是這(zhe)篇文(wen)章需要(yao)分享的Skeleton Screen,中文(wen)稱之(zhi)為"骨架(jia)屏"
A skeleton screen is essentially a blank version of a page into which information is gradually loaded.
在H5中,骨架(jia)屏其實(shi)已經(jing)不是什么新奇的(de)概(gai)念了,網上也有各(ge)種方案生成(cheng)對應(ying)的(de)骨架(jia)屏,包括我(wo)們經(jing)常使用(yong)(yong)的(de)知乎、餓了么、美團等APP都(dou)有應(ying)用(yong)(yong)骨架(jia)屏這個概(gai)念
圖片來源網絡(luo),侵刪

先從H5生(sheng)成骨架屏方案(an)開始(shi)說(shuo)(shuo)起,總的來說(shuo)(shuo)H5生(sheng)成骨架屏的方案(an)有2種
第一(yi)套方案,毫無疑問是最簡單最直白的方式,缺(que)點也很明顯(xian),假(jia)如頁面布(bu)局有修改的話,那么除了(le)修改業務(wu)代碼之外還需要額(e)外修改骨(gu)架(jia)屏,增加了(le)維護(hu)的成本。
第(di)二套方案,一定程度上(shang)改(gai)善了(le)(le)第(di)一套方案帶來(lai)的維護成本增加(jia)的缺點,主(zhu)要還(huan)是使用工具(ju)預渲染頁(ye)(ye)面,獲取到DOM節點和樣式(shi),保留(liu)頁(ye)(ye)面結構(gou),覆蓋樣式(shi),生(sheng)成灰(hui)色塊蓋在原(yuan)有(you)文本、圖片或者是canvas等節點上(shang)面,最(zui)后(hou)(hou)將生(sheng)成的HTML和CSS打(da)包出(chu)來(lai),就是一個帶有(you)骨(gu)架屏的頁(ye)(ye)面。最(zui)后(hou)(hou)再利用webpack工具(ju)將生(sheng)成的骨(gu)架屏插入到HTML里(li)面,詳細的話可以(yi)看(kan)看(kan)餓(e)了(le)(le)么的分享,這(zhe)里(li)就不多描(miao)述了(le)(le)。
調研了(le)下H5生(sheng)成骨架屏(ping)的方案,對于小程序生(sheng)成骨架屏(ping)的方案也有(you)了(le)一個大致(zhi)的想法,主要有(you)2個難(nan)點需要實現
再(zai)說回餓(e)了么提供(gong)的(de)骨(gu)架屏的(de)方案,使用(yong)(yong) puppeteer 渲(xuan)(xuan)染頁面(或(huo)者使用(yong)(yong)服務端渲(xuan)(xuan)染,vue或(huo)者react都有提供(gong)相(xiang)應的(de)方案),拿(na)到DOM節(jie)點(dian)(dian)和樣(yang)式,這里(li)有一(yi)點(dian)(dian)需(xu)要(yao)注(zhu)意(yi)的(de)是(shi),頁面的(de)渲(xuan)(xuan)染是(shi)需(xu)要(yao)初始(shi)化(hua)(hua)的(de)數據,數據的(de)來(lai)源可(ke)以是(shi)初始(shi)化(hua)(hua)的(de)data(vue)或(huo)者mock數據,當然小(xiao)程(cheng)序是(shi)無法直接(jie)使用(yong)(yong) puppeteer 來(lai)做預渲(xuan)(xuan)染(有另外的(de)方案可(ke)以實(shi)現),需(xu)要(yao)利用(yong)(yong)小(xiao)程(cheng)序初始(shi)化(hua)(hua)的(de) data + template 渲(xuan)(xuan)染之(zhi)后得(de)到一(yi)個初始(shi)化(hua)(hua)結構作為骨(gu)架屏的(de)結構
//index.js
Page({
data: {
motto: 'Hello World',
userInfo: {
avatarUrl: '//wx.qlogo.cn/mmopen/vi_32/SYiaiba5faeraYBoQCWdsBX4hSjFKiawzhIpnXjejDtjmiaFqMqhIlRBqR7IVdbKE51npeF6X1cXxtDQD2bzehgqMA/132',
nickName: 'jay'
},
lists: [
'aslkdnoakjbsnfkajbfk',
'qwrwfhbfdvndgndghndeghsdfh',
'qweqwtefhfhgmjfgjdfghaefdhsdfgdfh',
],
showSkeleton: true
},
onLoad: function () {
const that = this;
setTimeout(() => {
that.setData({
showSkeleton: false
})
}, 3000)
}
})
//index.wxml
<view class="container">
<view class="userinfo">
<block>
<image class="userinfo-avatar skeleton-radius" src="{{userInfo.avatarUrl}}"
mode="cover"></image>
<text class="userinfo-nickname skeleton-rect">{{userInfo.nickName}}</text>
</block>
</view>
<view style="margin: 20px 0">
<view wx:for="{{lists}}" class="lists">
<icon type="success" size="20" class="list skeleton-radius"/>
<text class="skeleton-rect">{{item}}</text>
</view>
</view>
<view class="usermotto">
<text class="user-motto skeleton-rect">{{motto}}</text>
</view>
<view style="margin-top: 200px;">
aaaaaaaaaaa
</view>
</view>
|
有(you)了上面(mian)的(de) data + template 之后,就有(you)了一個初始化(hua)的(de)頁面(mian)結構,接下(xia)來就需(xu)要拿(na)到節點(dian)信息
小程序基礎庫1.4.0之后小程序基礎庫提供了一組新的API,可用于獲取節點信息,具體API戳這里。
跟(gen)H5方式一樣,根據class或者id獲取節(jie)點(dian)信息(xi)(xi),不(bu)同的是只能獲取到當前的節(jie)點(dian)信息(xi)(xi),無法(fa)獲取到其父(fu)或者子(zi)節(jie)點(dian)信息(xi)(xi),所以只能手(shou)動給需要渲(xuan)染骨(gu)架屏的節(jie)點(dian)添加相應的class或者id
<view class="container">
<view class="userinfo">
<block>
<image class="userinfo-avatar skeleton-radius" src="{{userInfo.avatarUrl}}"
mode="cover"></image>
<text class="userinfo-nickname skeleton-rect">{{userInfo.nickName}}</text>
</block>
</view>
<view style="margin: 20px 0">
<view wx:for="{{lists}}" class="lists">
<icon type="success" size="20" class="list skeleton-radius"/>
<text class="skeleton-rect">{{item}}</text>
</view>
</view>
<view class="usermotto">
<text class="user-motto skeleton-rect">{{motto}}</text>
</view>
<view style="margin-top: 200px;">
aaaaaaaaaaa
</view>
</view>
|
約定2個特殊的class作(zuo)為獲取(qu)(qu)節點(dian)信息的標記(ji)skeleton-rect和skeleton-radius,在頁(ye)面中(zhong)獲取(qu)(qu)相應(ying)的top、left、width、height進(jin)行骨架屏的繪制

具體的(de)調用方式和(he)源碼(ma),請看 github ,最后求start
上文有說到小程序也可以使用 page-skeleton-webpack-plugin 方式一樣生成骨架屏,最重要的一點就是需要將小程序跑在chrome上面,后面的流程就一樣了,至于怎么將小程序跑在chrome上面呢?可以利用 wept ,缺點就是目前作者已經停止維護這個工具了,不支持新版小程序的API。
說回來我這個生成骨架(jia)(jia)(jia)屏(ping)的(de)方案(an),其實跟 page-skeleton-webpack-plugin 有(you)點(dian)(dian)相似,不同(tong)的(de)是(shi),page-skeleton-webpack-plugin 采用離線渲染(ran)的(de)方式生成靜態骨架(jia)(jia)(jia)屏(ping)插入路由中,而我采用運行時先渲染(ran)頁(ye)面(mian)(mian)默認(ren)(ren)結(jie)構(gou),然后根據(ju)默認(ren)(ren)結(jie)構(gou)再繪制骨架(jia)(jia)(jia)屏(ping)。從性能角(jiao)度出發確實不如 page-skeleton-webpack-plugin,但是(shi)也差(cha)不了(le)多少了(le),主要(yao)(yao)還(huan)是(shi)小(xiao)程序并沒有(you)提供類似服務端渲染(ran)的(de)方案(an)。目前從使用上(shang)來講(jiang),還(huan)是(shi)有(you)點(dian)(dian)小(xiao)麻煩,需(xu)要(yao)(yao)默認(ren)(ren)數(shu)據(ju)撐開頁(ye)面(mian)(mian)結(jie)構(gou),需(xu)要(yao)(yao)給相應的(de)節點(dian)(dian)添加(jia)class,后面(mian)(mian)有(you)時間再研(yan)究下有(you)沒有(you)更好的(de)方案(an)吧~~~