1. 程式人生 > >微信小程式:如何在小程式中使用骨架屏?

微信小程式:如何在小程式中使用骨架屏?

前言

骨架屏,就是在頁面資料尚未載入前,先給使用者展示出頁面的大致結構,直到請求資料返回後,再渲染頁面,以優化使用者體驗。

骨架屏在前端的應用已經很普遍了,之前接手vue的專案,沒能用上,現在開發小程式,想在小程式中試一試。看著美團外賣小程式的骨架屏,很nice~

開始

沒有使用骨架屏的經驗,只能靠搜尋引擎了。找找找....終於在網上找到一份很好的例子,作者是騰訊的,程式碼已經在github開源,現在介紹給大家。

首先,從github克隆專案到本地,看看效果啦~(在微信開發工具開啟專案下的src目錄)


效果圖(載入中):
渲染中

效果圖(載入完畢):
載入完畢


專案的目錄結構:
目錄結構
index.wxml:

<!-- 作為元件在頁面中使用 -->
<skeleton selector="skeleton"
loading="spin"
bgcolor="#FFF"
wx:if="{{showSkeleton}}"></skeleton>

<!--index.wxml-->
<!-- 渲染的根節點,加上 .skeleton -->
<view class="container skeleton">
    <view class="userinfo">
        <block>
            <!-- 要渲染的圓形節點,加上 .skeleton-radius -->
            <image class="userinfo-avatar skeleton-radius" src="{{userInfo.avatarUrl}}" mode="cover"></image>
            <!-- 要渲染的矩形節點,加上 .skeleton-rect -->
            <text class="userinfo-nickname skeleton-rect">{{userInfo.nickName}}</text>
        </block>
    </view>
    <view style="margin: 20px 0">
        <view wx:for="{{lists}}" wx:key="{{index}}" 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>

index.json:

{
  // 引入骨架屏元件
  "usingComponents": {
    "skeleton": "/component/skeleton/skeleton"
  }
}

最後來探索一下骨架屏元件的實現

skeleton.wxml:

<!-- 最外層的view綁定了js中定義的寬、高以及背景顏色 -->
<view style="width: {{systemInfo.width}}px; height: {{systemInfo.height}}px; background-color: {{bgcolor}}; position: absolute; left:0; top:0; z-index:9998; overflow: hidden;">
  <!-- 迴圈,遍歷繪製矩形節點,寬高參照js獲取到的節點寬高,以絕對定位的方式定位 -->
  <view wx:for="{{skeletonRectLists}}" wx:key="{{index}}" class="{{loading == 'chiaroscuro' ? 'chiaroscuro' : ''}}" style="width: {{item.width}}px; height: {{item.height}}px; background-color: rgb(194, 207, 214); position: absolute; left: {{item.left}}px; top: {{item.top}}px"></view>
  <!-- 迴圈,遍歷繪製矩形節點,寬高參照js獲取到的節點寬高,以絕對定位的方式定位 -->
  <view wx:for="{{skeletonCircleLists}}" wx:key="{{index}}" class="{{loading == 'chiaroscuro' ? 'chiaroscuro' : ''}}" style="width: {{item.width}}px; height: {{item.height}}px; background-color: rgb(194, 207, 214); border-radius: {{item.width}}px; position: absolute; left: {{item.left}}px; top: {{item.top}}px"></view>
  <view class="spinbox" wx:if="{{loading == 'spin'}}">
    <view class="spin"></view>
  </view>
</view>

skeleton.js:

Component({
  // 元件對外暴露的屬性
  properties: {
    // 背景顏色
    bgcolor: {
      type: String,
      value: '#FFF'
    },
    // 渲染的根節點的類名
    selector: {
      type: String,
      value: 'skeleton'
    },
    // 載入動畫
    loading: {
      type: String,
      value: 'spin'
    }
  },
  data: {
    loadingAni: ['spin', 'chiaroscuro'],
    systemInfo: {},
    skeletonRectLists: [],
    skeletonCircleLists: []
  },
  attached: function() {
    //預設的首屏寬高,防止內容閃現
    const systemInfo = wx.getSystemInfoSync();
    // 獲取系統的資訊,作為skeleton的寬和高
    this.setData({
      systemInfo: {
        width: systemInfo.windowWidth,
        height: systemInfo.windowHeight
      },
      // 設定動畫
      loading: this.data.loadingAni.includes(this.data.loading) ? this.data.loading: 'spin'
    })

  },
  ready: function() {
    const that = this;

    //繪製背景
    // selectAll: 在當前頁面下選擇匹配選擇器 selector 的所有節點。
    wx.createSelectorQuery().selectAll(`.$ {
      this.data.selector
    }`).boundingClientRect().exec(function(res) {
      console.log(res);
      that.setData({
        'systemInfo.height': res[0][0].height + res[0][0].top
      })
    });

    //繪製矩形
    this.rectHandle();

    //繪製圓形
    this.radiusHandle();
  },
  methods: {
    rectHandle: function() {
      const that = this;

      //繪製不帶樣式的節點
      // 選擇所有 .skeleton-rect的節點
      wx.createSelectorQuery().selectAll(`.$ {
        this.data.selector
      } - rect`).boundingClientRect().exec(function(res) {
        console.log(res);
        // 儲存資料,一維陣列是節點,二維陣列是節點的資訊
        that.setData({
          skeletonRectLists: res[0]
        })

        console.log(that.data);
      });
    },
    radiusHandle: function() {
      const that = this;
      // 同樣地選擇所有的 .skeleton-radius節點
      wx.createSelectorQuery().selectAll(`.$ {
        this.data.selector
      } - radius`).boundingClientRect().exec(function(res) {
        console.log(res);
        that.setData({
          skeletonCircleLists: res[0]
        })
        console.log(that.data);
      });
    },
  }
})

核心的程式碼是元件的.js和.wxml檔案,使用了wx.createSelectorQuery().selectAll 非常巧妙地選擇到了所有要渲染的矩形和圓形節點,在頁面中,使用迴圈,遍歷出所有的節點。

總結

就是這麼簡單的操作,實現了我們想要的效果。有時間真的應該好好看一些優秀的原始碼~

最後上一張使用的效果圖,要去吃飯了....

使用

如果你還有什麼疑問或想法,歡迎留言評論,或者掃描下方二維碼,與我取得聯絡~  (記得備註:CSND喔~)