微信小程序之圓形進度條(自定義組件)

前言

昨天在微信小程序實現了圓形進度條,今天想把這個圓形進度條作成一個組件,方便之後直接拿來用。
根據官方文檔自定義組件一步一步來html

建立自定義組件

第一步建立項目結構

打開微信開發者工具建立一個項目,
新建目錄 components 與 pages 目錄同級
在components中新建一個目錄circle
在circle中新建 Component 命名爲 circle 自動生成 json wxml wxss js 4個文件。
結構以下:
clipboard.pnggit

第二步編寫組件

編寫json

首先須要在 json 文件中進行自定義組件聲明(將 component 字段設爲 true 可這一組文件設爲自定義組件)github

{
  "component": true
}

編寫wxml和wxss

同時,還要在 wxml 文件中編寫組件模版,在 wxss 文件中加入組件樣式, 這裏我就編寫圓環進度條的 模板和樣式,參見微信小程序之圓形進度條
要注意canvas繪製的是px爲單位的,因此這裏我統一用px單位;其中size是根據canvas繪製的圓環的直徑,後面在js中會提到。
在組件的wxml中能夠包含 slot 節點,用於承載組件使用者提供的wxml結構。json

<!-- 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選擇器、屬性選擇器和標籤名選擇器。canvas

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

編寫js

在自定義組件的 js 文件中,須要使用 Component() 來註冊組件,並提供組件的屬性定義、內部數據和自定義方法。
組件的屬性值和內部數據將被用於組件 wxml 的渲染,其中,屬性值是可由組件外部傳入的。更多細節參見 Component構造器小程序

/* components/circle/circle.js */
Component({
  options: {
    multipleSlots: true // 在組件定義時的選項中啓用多slot支持
  },
  properties: {
    bg: {            // 屬性名
      type: String,   // 類型(必填),目前接受的類型包括:String, Number, Boolean, Object, Array, null(表示任意類型)
      value: 'bg'     // 屬性初始值(可選),若是未指定則會根據類型選擇一個
    },
    draw: {
      type: String,
      value: 'draw'
    },
  },

  data: { /*  私有數據,可用於模版渲染 */
    size: 0, /* 圓環盒子大小 size >= 2*x ( x 爲canvas的繪製半徑)*/
    step: 1,
    num: 100
  },
  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,this)
      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,this);
      // 設置漸變
      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()
    },
    /* 內部私有方法建議如下劃線開頭 ,
    * 自定義組件觸發事件時,須要使用 triggerEvent 方法,指定事件名、detail對象和事件選項 */
    _runEvent() {
      //觸發自定義組件事件
      this.triggerEvent("runEvent")
    }
  },

  // 生命週期函數,能夠爲函數,或一個在methods段中定義的方法名
  onReady: function () {
  }
})

自定義組件圓形進度條到此已經完成,segmentfault

使用自定義組件

下面咱們在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. circle1 = this.selectComponent("#circle1");
    // 繪製背景圓環
    this. circle1.drawCircleBg('circle_bg1', 100, 8)
    // 繪製彩色圓環 
    // this. circle1.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);
clipboard.png clipboard.png clipboard.png

`接下來要寫定時器方法了,在定時器中每隔一段時間調用一次 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.circle1.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

//index.js
//獲取應用實例
const app = getApp()
Page({
  data: { 
    num:100,
    step:null,
    time:null,
    stepTimer:null,
  },
  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
        });
                clearInterval(this.stepTimer);
      }
    }, 100) 
  },
  changeTime:function(){
    // 先清除定時器
    clearInterval(this.stepTimer);
    // 計數器 還原到100
    this.setData({
      num: 100
    });
    // 從新開啓倒計時
    this.stepInterval()
    // 觸發自定義組件事件
    this._runEvent()
  },
  onLoad: function () {
  },
  onReady: function () {
    /*倒計時*/
    // 得到circle組件
    this.circle = this.selectComponent("#circle");
    // 繪製背景圓環
   // this.circle.drawCircleBg('circle_bg', 40, 4)
    // 繪製彩色圓環
    this.stepInterval()
  },
  
  _runEvent() {
     console.log(1111) 
  },
})

效果圖
圖片描述

若感興趣,請下載 完整項目

因爲版本庫升級作對應的更新以及bug修復(20190716)

一、components/circle/circle.js文件中, wx.createCanvasContext(id) 改成:
wx.createCanvasContext(id,this);

二、index.js中屢次調用時獲取circle組件使用不一樣變量 this.circle = this.selectComponent("#circle"); this.circle1 = this.selectComponent("#circle1");

相關文章
相關標籤/搜索