小程式之骨架屏

Annter發表於2020-03-23

骨架屏

在小程式中,頁面層與邏輯層通訊,還有伺服器端通訊需要一定的時間,這為使用者的體驗帶來不小的挑戰。

為了減少使用者等待的焦慮,以及減少使用者離開頁面的時間。所以讓使用者提前感知此頁面在執行,和使用者提前聚焦內容,於是使用骨架屏作為初次渲染。


繪製骨架

骨架元素分為兩種:

  • 圓形
  • 長方形

長方形的繪製:

<div class="rect"></div>
<style>
  .rect {
    height: 20rpx;
    width: 100vw;
    background-color: #dcdde1;
  }
</style>
複製程式碼

圓形只需要在正方形的基礎上加上border-radius:100%即可,例子如下:

<div class="cir"></div>
<style>
  .cir {
    height: 50rpx;
    width: 50rpx;
    background-color: #dcdde1;
    border-radius: 100%;
  }
</style>
複製程式碼

繪製的骨架

在小程式中,提供selectAll這個API可以幫我選擇出頁面中的元素。

選擇整個頁面中的.rect元素,我們將其包裝成非同步的模式:

async function selectAll(selector) {
  return new Promise((resolve, reject) => {
    uni
      .createSelectorQuery()
      .selectAll(selector)
      .boundingClientRect()
      .exec(res => resolve(res));
  });
}
複製程式碼

然後就可以使用selectAll函式選擇頁面中的元素。

定位元素

頁面中的元素定位有多種,但是骨架屏因為它不會運動,不會左右搖晃,更不會變色。

所以在頁面中使用絕對定位,可以精確找到落在頁面上的元素。

<div class="skeleton-contain">
  <div class="rect"></div>
</div>
<style>
  .skeleton-contain {
    height: 100vw;
    width: 100vw;
    position: absolute;
  }
  .rect {
    top: 20rpx;
    height: 20rpx;
    width: 100vw;
    background-color: #dcdde1;
  }
</style>
複製程式碼

由於前面的selectAll函式,那麼它返回的欄位形如:

{
  "bottom": 262,
  "dataset": Object,
  "height": 60,
  "id": "",
  "left": 37.5,
  "right": 97.5,
  "top": 202,
  "width": 60
}
複製程式碼

這時,我們就可以找到它的定位點在哪裡,並以迴圈節點的方式繪製:

<template>
  <view class="skeleton-contain">
    <view
      v-for="(item, index) in rectList"
      :key="index"
      class="rect"
      :style="[
        {
          height: `${item.height}px`,
          width: `${item.width}px`
        },
        {
          top: `${item.top}px`,
          bottom: `${item.bottom}px`,
          right: `${item.right}px`,
          left: `${item.left}px`
        }
      ]"
    ></view>
  </view>
</template>
<script>
export default {
  name: 'skeleton',
  mounted() {
    this.drawRect();
  },
  data() {
    return {
      rectList: []
    };
  },
  methods: {
    async selectAll(selector) {
      return new Promise((resolve, reject) => {
        uni
          .createSelectorQuery()
          .selectAll(selector)
          .boundingClientRect()
          .exec(res => resolve(res));
      });
    },
    async drawRect() {
      const [rect] = await this.selectAll('.rect');
      this.rectList = rect;
    }
  }
};
</script>
<style>
.skeleton-contain {
  height: 100vw;
  width: 100vw;
  position: absolute;
}
.rect {
  background-color: #dcdde1;
}
</style>
複製程式碼

這樣,一個完整的骨架也就做出來了。

相關文章