美文网首页让前端飞F2e踩坑之路前端之美-小程序
微信小程序内如何实现骨架屏效果

微信小程序内如何实现骨架屏效果

作者: 人类进化又没带我 | 来源:发表于2019-09-28 12:07 被阅读0次
    首先了解下什么是骨架屏?

    骨架屏就是在页面数据尚未加载前先给用户展示出页面的大致结构,直到请求数据返回后再渲染页面,补充进需要显示的数据内容。常用于文章列表、动态列表页等相对比较规则的列表页面。 很多项目中都有应用饿了么h5版本,知乎,facebook等网站中都有应用。
    以下图举例,常用饿了么的童鞋,应该看到过饿了么的这个首页预加载图的效果:
    饿了么h5实现方案

    网上查找的饿了么的图,如侵权联系删除.png
    咱们来聊聊小程序的实现方案:
    1.最简单最快捷的最暴力的,直接让设计一张图片盖上去,当loading使用。

    举例:饿了么的订单页面,查看了下源码,是使用的SVG的图


    image.png
    2.前端使用view写死一套数据(缺点很明显,假如页面布局有修改的话,那么除了修改业务代码之外还需要额外修改骨架屏,增加了维护的成本)

    举例:简单写了个代码片段:https://developers.weixin.qq.com/s/ZAuYzHmX7ObC

    image.png
    3.页面Data里写死一套默认数据,使用小程序的wx.createSelectorQuery().selectAll 选择了所有要渲染的矩形和圆形节点,在页面中,使用循环,遍历出所有的节点,再加上样式。
    基本原理就是
    • 在组建初始化时,设置其绝对定位,大小为整个屏幕大小
    • 然后用节点查询方法,找到类名等于skeleton的元素,并设置组件的背景的位置及大小和元素的一致,覆盖这个元素。
    • 用节点查询方法,找到所有的类名等于skeleton-radius 元素,并将它们的位置及大小信息加入到sklection-radius-Arr数组中,在wxml中用wx:for循环渲染出来(也是绝对定位)
    • 用节点查询方法,找到所有的类名等于skeleton-rect 元素,并将它们的位置及大小信息加入到sklection-rect-Arr数组中,在wxml中用wx:for循环渲染出来(也是绝对定位)

    当然啦,这里还有一些判断,还可以设置屏幕上提示是旋转小圈圈还是背景色渐变提醒等,都是一些比较细节的东西,就不细说。
    具体代码参考:jayZOU,这里有他具体源码以及实现逻辑,使用后会发现有些许异常未处理。

    那么到这就完了吗?当然木有,现在说下最后一种方案(目前我们小程序正在使用的方案)。

    4. 如何更好的把骨架屏代码嵌入到业务里面,是否可以在接口请求成功后,先渲染出一套接口返回的数据匹配的骨架,再展示给用户看呢,减少用户查看白屏(loading)时间。

    这是我们线上版本效果示例图:

    image.png
    首先来看 如何操作:
    整个前边部分跟jayZOU的逻辑思路一样,使用wx.createSelectorQuery 获取到相关节点进行渲染操作,但是我们把默认数据这一栏更改为动态数据,并且兼容修复了一部分bug。
    核心代码就是自定义组件内抛出的isNodes和isComplete属性
    //wxml
    <skeletons isNodes="{{isNodes}}" isComplete="{{isComplete}}"" />
    //页面节点上需要手动添加一个样式类。
    比如轮播图 宽686rpx,高140rox,是长方形那么给他的样式上加上‘skeletions-rect’,如果是圆形给他加上‘skeletons-circle’
    
    
    业务内代码如下:
    <!-- 轮播图组件 -->
      <block wx:if="{{swiperData.length > 0}}">
        <swiper class="swiperSlide" indicator-dots="{{indicatorDots}}" indicator-color="#ccc" indicator-active-color="#00CC88" autoplay circular>
          <block wx:for="{{swiperData}}" wx:key="{{index}}">
            <swiper-item>
              <view class="swiper-item">
                <image lazy-load src="{{item.image}}" data-index="{{index}}" bindtap="universalJump" class="skeletons-rect" />
              </view>
            </swiper-item>
          </block>
        </swiper>
        <!-- <qts-swiper resourseFrom="{{swiperData}}" indicatorDots="{{indicatorDots}}"></qts-swiper> -->
      </block>
    
    相关JS如下:
      initData() {
        let postData = {
            townId: wx.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('团团开小差啦,请稍后重试')
        })
      },
    
    目前遇到的难点在于,把功能点抽成自定义组件。skeletons的class类无法传递进去,试过用外部样式影响自定义组件样式,还是无法达到效果。如果有解决这个问题的欢迎留言沟通优化~

    最后完整组件代码地址:https://gitee.com/minchangyong/skeletons

    相关文章

      网友评论

        本文标题:微信小程序内如何实现骨架屏效果

        本文链接:https://www.haomeiwen.com/subject/wvnzuctx.html