评论

【已废弃】如何在微信、支付宝小程序内实现骨架屏效果(建议使用官方工具自带的骨架屏功能)

如何在微信小程序内实现骨架屏效果,怎么实现在更贴合业务的情况去优化用户体验。

新版本开发者工具已支持骨架屏了,可自行尝试下~

首先了解下什么是骨架屏?

骨架屏就是在页面数据尚未加载前先给用户展示出页面的大致结构,直到请求数据返回后再渲染页面,补充进需要显示的数据内容。常用于文章列表、动态列表页等相对比较规则的列表页面。 很多项目中都有应用饿了么h5版本,知乎,facebook等网站中都有应用。

老规矩,先看我们的效果图:

以下图举例,常用饿了么的童鞋,应该看到过饿了么的这个首页预加载图的效果:
饿了么h5实现方案

咱们来聊聊小程序的实现方案:

1.最简单最快捷最暴力的,直接让设计一张图片盖上去,当loading使用。

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

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

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

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)时间。(缺点是如果请求挂掉,骨架屏是不会渲染出来的)

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

首先来看 如何操作:
整个前边部分跟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
已实现支付宝小程序骨架屏

具体效果可以搜索《青团社兼职》小程序查看。

最后一次编辑于  2020-06-30  
点赞 44
收藏
评论

7 个评论

  • r=a(1 - sinθ)
    r=a(1 - sinθ)
    2019-10-12

    EMMMMM好难啊o(╥﹏╥)o

    2019-10-12
    赞同 1
    回复 3
    • 九歌^
      九歌^
      2019-10-14
      ???难什么,拷贝代码后在你的业务页面加入组件就好了啊
      2019-10-14
      3
      回复
    • r=a(1 - sinθ)
      r=a(1 - sinθ)
      2019-10-14回复九歌^
      好~我要加油努力学习
      2019-10-14
      回复
    • 九歌^
      九歌^
      2019-10-14回复r=a(1 - sinθ)
      加油⛽️
      2019-10-14
      3
      回复
  • Huān
    Huān
    2020-08-15

    骨架屏只能首屏的时候?分页怎么实现呢

    2020-08-15
    赞同
    回复 1
    • 九歌^
      九歌^
      2020-08-17
      是的,没看过分页还需要有骨架屏的需求。
      2020-08-17
      1
      回复
  • 猛男陈阔
    猛男陈阔
    2020-05-09

    感觉目前你们的骨架屏只为了实现骨架屏而做骨架屏,并不是为了解决项目中请求等待时间过长的这一痛点,刚看了你们github发布的代码,接口请求之前是存在一个loading,也就是说接口已经请求成功了,但是你们还要等待节点绘画完成再去做骨架屏处理,这样大大的影响了用户的等待时间,感觉不是一套很好的解决方案,个人观点,勿喷

    2020-05-09
    赞同
    回复 7
    • 九歌^
      九歌^
      2020-05-09
      这是为了解决接口数据返回后渲染到页面那一层,页面无默认数据时布局异常问题。
      2020-05-09
      2
      回复
    • 九歌^
      九歌^
      2020-05-09
      我们现在用开发者工具自带的骨架屏功能了。
      2020-05-09
      3
      回复
    • 猛男陈阔
      猛男陈阔
      2020-05-11回复九歌^
      加油
      2020-05-11
      回复
    • 九歌^
      九歌^
      2020-05-11
      最初一版本是在本地data里写死数据,通过以上方法骨架渲染。后来因为某些页面首页有定时器。即使接口请求成功了内容格式转换也是空白,所以加了个过渡。
      2020-05-11
      4
      回复
    • 九歌^
      九歌^
      2020-05-11回复猛男陈阔
      目前官方采用的是这种方式。
      2020-05-11
      回复
    查看更多(2)
  • 2020-04-14

    你好,假如遇到接口请求数据速度过慢的情况下,是不是会有白屏的情况?

    2020-04-14
    赞同
    回复 4
    • 九歌^
      九歌^
      2020-04-14
      不会,我加了个gif,其实现在这种方案效果不好。可以换为本地data里写死数据。
      2020-04-14
      4
      回复
    • 九歌^
      九歌^
      2020-04-14
      https://wux-weapp.github.io/wux-weapp-docs/#/skeleton
      2020-04-14
      2
      回复
    • 2020-04-14回复九歌^
      好的  感谢
      2020-04-14
      回复
    • 九歌^
      九歌^
      2020-04-14回复
      客气~
      2020-04-14
      2
      回复
  • hi修修
    hi修修
    2019-12-30
    自定义组件可是实现了,但是现在想 开发一个插件供其他小程序使用 里面的 createSelectorQuery().selectAll() 获取不到节点,遇到过吗
    
    2019-12-30
    赞同
    回复 3
    • 九歌^
      九歌^
      2019-12-30
      没开发过插件,还不清楚。最近有点忙
      2019-12-30
      4
      回复
    • hi修修
      hi修修
      2019-12-30回复九歌^
      好的 感谢,我也是在不断尝试
      2019-12-30
      回复
    • 九歌^
      九歌^
      2019-12-30回复hi修修
      有空可以试试,现在年底了有个大项目,都没空逛社区了。
      2019-12-30
      4
      回复
  • o0o有脾气的酸奶
    o0o有脾气的酸奶
    2019-11-18

    自定义组件不是可以传页面的样式名进去吗

    页面A skeleton 的样式名为 .skeleton,自定义组件为aaa

    externalClasses:['skeleton-class']

    页面A wxml

    <aaa skeleton-class="skeleton"></aaa >


    自定义组件为aaa wxml

    <view class="skeleton-class"></view>


    2019-11-18
    赞同
    回复 10
    查看更多(5)
  • JIang
    JIang
    2019-10-14

    一个场景,首页纯组件拼接,结构都是动态的,这样的骨架屏该怎么搞,望楼主不吝赐教

    2019-10-14
    赞同
    回复 4
    • 九歌^
      九歌^
      2019-10-14
      首页纯组件 是 我最开始的方案,所有模块点 全抽成组件,我在文档最后写了组件的class类无法传递进去,目前方案是首屏的不做成自定义组件,有好的方法欢迎讨论
      2019-10-14
      4
      回复
    • 九歌^
      九歌^
      2019-10-14
      现在首屏的都不是自定义组件,第二屏开始才是
      2019-10-14
      3
      回复
    • ᴴᴱᴸᴸᴼ
      ᴴᴱᴸᴸᴼ
      2019-11-12回复九歌^
      也就是说目前骨架屏无法做到适配所有不同结构的页面吗,我之前也尝试过,后面没能做到(菜到模糊)
      2019-11-12
      回复
    • 九歌^
      九歌^
      2019-11-12回复ᴴᴱᴸᴸᴼ
      是的,只要有自定义组件 组件样式无法做到穿透。需要页面展示的内容 无自定义组件才可以
      2019-11-12
      4
      回复
登录 后发表内容