1. 程式人生 > >開發 | 手把手,教你在小程式裡做一個圓形進度條

開發 | 手把手,教你在小程式裡做一個圓形進度條

今天想把之前在微信小程式開發過程中,製作的一個圓形進度條做成一個元件,方便以後直接拿來用。

建立自定義元件

一、建立專案結構

開啟微信開發者工具建立一個專案, 新建 與 pages 同級目錄 components,在 components 中新建一個目錄 circle ,circle 中新建 Component 命名為 circle,此時將自動生成 jsonwxml、wxssjs 4 個檔案。結構如下:

二、編寫元件

首先需要在 json 檔案中進行自定義元件宣告(將 component 欄位設為 true,可將這一組檔案設為自定義元件)。

{
"component": true
}

同時,還要在 wxml

 檔案中編寫元件模版,在 wxss 檔案中加入元件樣式,這裡編寫圓環進度條的模板和樣式,參見微信小程式之圓形進度條。

要注意 canvas 繪製的是 px 為單位的,所以這裡統一用 px 單位;其中 size 是根據 canvas 繪製的圓環的直徑,後面在 js 中會提到。

在元件的 wxml 中可以包含 slot 節點,用於承載元件使用者提供的 wxml 結構。

<!-- components/circle/circle.wxml -->
<view class="circle_box" style="width:{{size}}px;height:{{size}}px">
          <canvas
class="circle_bg" canvas-id="
{{bg}}" style="width:{{size}}px;height:{{size}}px"></canvas> <canvas class="circle_draw" canvas-id="{{draw}}" style="width:{{size}}px;height:{{size}}px"></canvas> <slot></slot> </view>

注意:在元件 wxss 中不應使用 ID 選擇器、屬性選擇器和標籤名選擇器。

/* components/circle/circle.wxss */
.circle_box,.circle_draw{ position: relative; }
.circle_bg{position: absolute;}

編寫 js

在自定義元件的 js 檔案中,需要使用 Component() 來註冊元件,並提供元件的屬性定義、內部資料和自定義方法。

元件的屬性值和內部資料將被用於元件 wxml 的渲染,其中,屬性值是可由元件外部傳入的。更多細節參考 。

/* components/circle/circle.js */
Component({
  ……
  methods: {
    /* id : canvas 元件的唯一識別符號 canvas-id ,x : canvas 繪製圓形的半徑, w : canvas 繪製圓環的寬度  */
    drawCircleBg: function (id, x, w) {
      // 設定圓環外面盒子大小 寬高都等於圓環直徑
      this.setData({
        size: 2 * x
      });
      // 使用 wx.createContext 獲取繪圖上下文 ctx  繪製背景圓環
      var ctx = wx.createCanvasContext(id)
      ctx.setLineWidth(w / 2); ctx.setStrokeStyle('#20183b'); ctx.setLineCap('round')
      ctx.beginPath();//開始一個新的路徑
      //設定一個原點(x,y),半徑為r的圓的路徑到當前路徑 此處x=y=r
      ctx.arc(x, x, x - w, 0, 2 * Math.PI, false);
      ctx.stroke();//對當前路徑進行描邊
      ctx.draw();
    },
    drawCircle: function (id, x, w, step) {
      // 使用 wx.createContext 獲取繪圖上下文 context  繪製彩色進度條圓環
      var context = wx.createCanvasContext(id);
      // 設定漸變
      var gradient = context.createLinearGradient(2 * x, x, 0);
      gradient.addColorStop("0", "#2661DD"); gradient.addColorStop("0.5", "#40ED94"); gradient.addColorStop("1.0", "#5956CC");
      context.setLineWidth(w); context.setStrokeStyle(gradient); context.setLineCap('round')
      context.beginPath();//開始一個新的路徑
      // step 從0到2為一週
      context.arc(x, x, x - w, -Math.PI / 2, step * Math.PI - Math.PI / 2, false);
      context.stroke();//對當前路徑進行描邊
      context.draw()
    },
    _runEvent() {
      //觸發自定義元件事件
      this.triggerEvent("runEvent")
    }
  },
  ……
})

自定義元件圓形進度條到此已經完成。

使用自定義元件

下面我們在 index 中使用自定義元件圓形進度條。

一、json 檔案中進行引用宣告

使用已註冊的自定義元件前,首先要在頁面的 json 檔案中進行引用宣告。此時需要提供每個自定義元件的標籤名和對應的自定義元件檔案路徑:

{
  "usingComponents": {
    "circle": "/components/circle/circle"
  }
}

二、wxml 檔案中使用自定義元件

這樣,在頁面的 wxml 中就可以像使用基礎元件一樣使用自定義元件。節點名即自定義元件的標籤名,節點屬性即傳遞給元件的屬性值。

  • 節點名即自定義元件的標籤名:circle;
  • 節點屬性即傳遞給元件的屬性值:bg,draw;
  • 當自定義元件觸發 runEvent 事件時,呼叫_runEvent 方法。
<!--index.wxml-->
<view class="container">
    <circle id='circle1'
      bg='circle_bg1'
      draw='circle_draw1'
      bind:runEvent="_runEvent" >
        <!-- 這部分內容將被放置在元件 <slot> 的位置上 -->
        <view class="circle_info" bindtap="changeTime">
             <view class="circle_dot"></view>
             <text class='circle_txt'> {{txt}} </text>
       </view>
    </circle>
</view>

自定義元件的 wxml 節點結構在與資料結合之後,將被插入到引用位置內。在 wxss 給 slot 位置上的內容新增一些樣式。

/**index.wxss**/
/*圓環進度條文字*/
.circle_info{
  position: absolute; 
  width: 100%;
  left: 50%;
  top: 50%; 
  transform: translate(-50%,-50%); 
  display: flex;  
  align-items: center;
  justify-content: center
}
.circle_dot{
  width:16rpx;
  height: 16rpx;  
  border-radius: 50%;
  background-color: #fb9126;
} 
.circle_txt{
  padding-left: 10rpx;
  color: #fff;
  font-size: 36rpx; 
  letter-spacing: 2rpx;
}

三、js 檔案中呼叫自定義元件中的方法

在 wxml 中我們用到一個數據 {{txt}},我們需要在 js 中設定一下 data,然後在 onReady 中使用 selectComponent 選擇元件例項節點。

//index.js
 data: { 
    txt: "正在匹配中..." 
  },
 onReady: function () {
   // 獲得circle元件
    this.circle = this.selectComponent("#circle1");
    // 繪製背景圓環
    this.circle.drawCircleBg('circle_bg1', 100, 8)
    // 繪製彩色圓環 
    this.circle.drawCircle('circle_draw1', 100, 8, 2);  
  },

效果如下:
this.circle.drawCircle('circle_draw1', 100, 8, 0.5);

this.circle.drawCircle('circle_draw1', 100, 8, 1);

this.circle.drawCircle('circle_draw1', 100, 8, 2);

接下來要寫定時器方法了,在定時器中每隔一段時間呼叫一次 this.circle.drawCircle(id, x, w, step),通過改變 step 的值來動態繪製圓環。

  1. 在 data 中設定幾個初始值
  2. 定義一個定時器方法 countInterval,假設每隔 100 毫秒 count 遞增
    +1,當 count 遞增到 100 的時候剛好是一個圓環,然後改變 txt 值並且清除定時器
  3. 在 onReady 中呼叫這個定時器方法
  data: { 
    txt: "正在匹配中...",
    count: 0,//計數器,初始值為0
    maxCount: 100, // 繪製一個圓環所需的步驟 
    countTimer: null,//定時器,初始值為null
  },
   countInterval: function () {
    // 設定倒計時 定時器 假設每隔100毫秒 count遞增+1,當 count遞增到兩倍maxCount的時候剛好是一個圓環( step 從0到2為一週),然後改變txt值並且清除定時器
    this.countTimer = setInterval(() => {   
      if (this.data.count <= 2 * this.data.maxCount) {        
        // 繪製彩色圓環進度條
        this.circle.drawCircle('circle_draw1', 100, 8, this.data.count / this.data.maxCount)
        this.data.count++;
        } else {
        this.setData({
          txt: "匹配成功"
        });
         clearInterval(this.countTimer); 
      }
    }, 100)
  },
 onReady: function () {
   // 獲得circle元件
    this.circle = this.selectComponent("#circle1");
    // 繪製背景圓環
    this.circle.drawCircleBg('circle_bg1', 100, 8)
    // 繪製彩色圓環 
    // this.circle.drawCircle('circle_draw1', 100, 8, 2);  
    this.countInterval()
  },

最終效果

再次使用自定義元件做倒計時

count 可以遞增,當然可以遞減。這裡就不在贅述,直接上程式碼:
wxml

<circle id='circle'
bg='circle_bg'
draw='circle_draw'
bind:runEvent="_runEvent" >
  <view class="circle_text" bindtap="changeTime">
  <text class='circle_time'> {{time}} s</text></view>
</circle>

wxss

/*圓環倒計時*/
.circle_text{
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
}
.circle_time{
color: #fff;
font-size: 32rpx;
padding-left: 16rpx;
}

js

const app = getApp()
Page({
  ……
  stepInterval: function () {
    var n = this.data.num / 2  // 設定倒計時 定時器
    this.stepTimer = setInterval(() => {
      if (this.data.num >= 0) {
        this.data.step = this.data.num / n;
        this.circle.drawCircle('circle_draw', 40, 4, this.data.step)// 繪製彩色圓環進度條
        if ((/(^[1-9]\d*$)/.test(this.data.num / 10))) {
          this.setData({ // 當時間為整數秒的時候 改變時間
            time: this.data.num / 10
          });
        }
        this.data.num--;
      } else {
        this.setData({
          time: 0
        });
      }
    }, 100)
  },
  changeTime: function () {
    clearInterval(this.stepTimer);
    this.setData({
      num: 100
    });
    this.stepInterval() // 重新開啟倒計時
    this._runEvent() // 觸發自定義元件事件
  },
  ……
})

最終效果

關注「知曉程式」微信公眾號,回覆「開發」,讓你的小程式效能再上一層樓。