骨架屏的原理和使用

基本原理

FP: First Paint,首屏绘制时间。即从进入页面后(输入url后)到看见内容所经历的时间。

FMP:First Meaningful Paint,页面有意义的内容绘制。

这两个的区别可以这样简单理解:FP指的是从进入到绘制出任何内容的时间,而FMP则是指从进入到绘制出实际有意义的内容(任何我们希望用户看到的东西)的时间。

因此可以知道,FP即我们常说的白屏时间。FP并不要求内容是真实的,有效的,有意义的,可交互的。

何为骨架屏

骨架屏就是在页面内容未加载完成的时候,先使用一些图形进行占位,待内容加载完成之后再把它替换掉。

简单来说,骨架屏的作用和loading图其实是差不多的,只是看起来更为“高端”。相比之下骨架屏的好处在哪里?转一下大牛技术文章里的话

在 MIT 2014 年的研究中有提到,用户大概会在 200ms 内获取到界面的具体关注点,在数据获取或页面加载完成之前,给用户首先展现骨架屏,骨架屏的样式、布局和真实数据渲染的页面保持一致,这样用户在骨架屏中获取到关注点,并能够预知页面什么地方将要展示文字什么地方展示图片,这样也就能够将关注焦点移到感兴趣的位置。当真实数据获取后,用真实数据渲染的页面替换骨架屏,如果整个过程在 1s 以内,用户几乎感知不到数据的加载过程和最终渲染的页面替换骨架屏,而在用户的感知上,出现骨架屏那一刻数据已经获取到了,而后只是数据渐进式的渲染出来。这样用户感知页面加载更快了。

如何构建骨架屏

总得来说H5生成骨架屏的方案有2种

  1. 完全靠手写HTML和CSS方式给每个页面定制一套骨架屏。这个方法简单粗暴,但是无法复用,且如果页面布局有修改的话还需要额外修改骨架屏。
  2. 利用预渲染的方式生成静态骨架屏。主要方法是使用工具预渲染页面,获取到DOM节点和样式,保留页面结构,覆盖样式,生成灰色块盖在原有文本、图片或者是canvas等节点上面,最后将生成的HTML和CSS打包出来,就是一个带有骨架屏的页面。最后再利用webpack工具将生成的骨架屏插入到HTML页面,详细还是可以见上面说的饿了么分享

小程序实现方案

预渲染实现方法

这里写一个简单的例子

需要使用骨架屏的一个列表(假设节点里的数据需要接口请求):

<view class='skeleton'>
  <view class='skeleton-item'>这里是骨架屏{{xxx}}节点</view>
  <view class='skeleton-item'>这里是骨架屏{{xxx}}节点</view>
  <view class='skeleton-item'>这里是骨架屏{{xxx}}节点</view>
  <view class='skeleton-item'>这里是骨架屏{{xxx}}节点</view>
</view>

骨架屏组件skeleton.wxml:

<view
  style='height: {{body.height}}px; z-index:999'>
  <block wx:for="{{skeletonItems}}">
    <view
      class='skeleton-item'
      style="position:absolute;width:{{item.width}}px;height:{{item.height}}px;left:{{item.left}}px;right:{{item.right}}px"></view>
  </block>
</view>

骨架屏组件里的两个函数,在acctched时调用:

// 绘制背景
wx.createSelectorQuery().in(this).selectAll('.skeleton').boundingClientRect(res => {
    this.setData({
      'body.height': res[0][0].height + res[0][0].top
    });
  })
    .exec();

// 绘制节点
wx.createSelectorQuery().in(this).selectAll('.skeleton-item').boundingClientRect(res => {
    this.setData({
      skeletonItems: res[0]
    });
  })
    .exec();

用wx:if={{数据内容}}来确定组件的显示即可

实际采用的方案

事实上,上面的预渲染也只是非常简单的一个例子,实际的骨架屏组件WXML里的逻辑判断也会比较多。而且还有一点重要的是,这个方法需要初始化数据来获取节点的详细信息,不同的情况使用这个组件时都需要预先设定不同的数据,目前暂时我还没有想到解决方法。此外我还没有研究的是,在复杂页面的骨架屏显示,通过小程序的createSelectorQuery找到节点信息一一绘制,这之间所消耗的时间和请求到数据比起来的时间占比为多少?这个还需要之后有空时进一步实验。

小程序目前暂时用了粗暴手写定制的方法来实现骨架屏,虽然不是最理想的方法,但是胜在完全够用。很多情况下我并不需要对页面中所有节点都加上骨架屏,只需要对一小部分复用的组件(比如音乐列表里的item),那我针对这个music-item写一个非常小的定制骨架屏组件其实也未尝不可。

小结

这篇技术博客其实花费时间并不长,之后还需要详细完善,目前只是简单记录了一下小程序上在骨架屏的实现。我个人在vue、react等真正有成熟骨架屏方案上的学习还没有展开。学习之路漫漫长长~结尾就打一个未完待续吧

つづく

 小程序学习:前端渲染二维码分享海报
彻底弄懂 Http 缓存机制 - 基于缓存策略三要素分解法 
上一篇:小程序学习:前端渲染二维码分享海报
下一篇:彻底弄懂 Http 缓存机制 - 基于缓存策略三要素分解法


如果我的文章对你有帮助,或许可以打赏一下呀!

支付宝
微信
QQ