评论

使用canvas封装倒计时组件

canvas 2d 实现的倒计时微信小程序组件库

实现思路

  1. 使用canvas 2d接口,获取canvas示例
  2. 初始化画布大小
  3. 设置计时器,并在计时器中使用canvas.fillText绘制文本

仓库:https://github.com/bgmmd/canvas-count-down-wx-minapp.git

代码:

count.wxml

//count.wxml
<view>
  <canvas id="myCanvas" type="2d" style="height: {{height}};width:{{width}} ;" />
</view>

coutDown.js

// components/countDown/countDown.js
Component({

  /**
   * 组件的属性列表
   */
  properties: {
    total: {
      type: Number,
      value: 10
    },
    fontSize: {
      type: Number,
      value: 16
    },
    fontColor: {
      type: String,
      value: '#000'
    },
    width: {
      type: String,
      value: '100rpx'
    },
    height: {
      type: String,
      value: '100rpx'
    }
  },

  /**
   * 组件的初始数据
   */

  data: {
    timer: null,
    totalSecond: null,
    totalSecond: '',
    ctx: null,
    canvasWidth: '',
    canvasHeight: ''
  },
  lifetimes: {
    attached() {
      this.data.totalSecond = this.properties.total
      this.createSelectorQuery()
        .select('#myCanvas') // 在 WXML 中填入的 id
        .fields({
          node: true,
          size: true
        })
        .exec((res) => {
          // console.log(res)
          // Canvas 对象
          const canvas = res[0].node
          // Canvas 画布的实际绘制宽高
          const renderWidth = res[0].width
          const renderHeight = res[0].height
          // Canvas 绘制上下文
          this.data.ctx = canvas.getContext('2d')
          // 初始化画布大小
          const dpr = wx.getWindowInfo().pixelRatio
          canvas.width = renderWidth * dpr
          canvas.height = renderHeight * dpr
          this.data.canvasWidth = renderWidth
          this.data.canvasHeight = renderHeight
          this.data.ctx.scale(dpr, dpr)
          this.data.ctx.font = `${this.properties.fontSize}px sans-serif` //设置字体大小
          this.data.ctx.fillStyle = this.properties.fontColor //设置字体颜色
          // console.log(this.data.ctx)
          // console.log(this.data)
          this.data.ctx.textAlign = 'center' //设置居中
          this.data.ctx.fillText(this.data.totalSecond, this.data.canvasWidth / 2, this.data.canvasHeight / 2 + this.data.fontSize / 2) //这里是设置文本居中的方法,x坐标是canvas.width的一半,但是y坐标还要加上字体尺寸的一半是因为fillText绘制文本时是字体从下往上绘制的。设置fillText('xxx',0,0)会发现字体并没有在左上角,是因为相对于坐标(0,0)进行字体从下往上绘制,所以这里垂直居中还要加上字体尺寸的一半
        })
      
    },
  },

  /**
   * 组件的方法列表
   */
  methods: {
    start() {
      if(this.data.totalSecond<=0)return
      const that = this
      this.data.timer = setInterval(() => {
        this.data.totalSecond = this.data.totalSecond - 1
        this.data.ctx.clearRect(0, 0, this.data.canvasWidth, this.data.canvasHeight) //清除画布,避免上次绘制文本与此次重叠
        this.data.ctx.fillText(this.data.totalSecond, this.data.canvasWidth / 2, this.data.canvasHeight / 2 + this.data.fontSize / 2)
        if (this.data.totalSecond <= 0) {
          clearInterval(this.data.timer)
          this.triggerEvent('countEnd')
        }
      }, 1000)
    },
    pause(){
      if(!this.data.timer) return
      clearInterval(this.data.timer)
      this.triggerEvent('countPause')
    },
    reset(){
      if(this.data.totalSecond==this.properties.total) return
      if(!this.data.timer) return
      clearInterval(this.data.timer)
      this.data.totalSecond = this.properties.total
      //重新绘制
      this.data.ctx.clearRect(0, 0, this.data.canvasWidth, this.data.canvasHeight) //清除画布,避免上次绘制文本与此次重叠
      this.data.ctx.fillText(this.data.totalSecond, this.data.canvasWidth / 2, this.data.canvasHeight / 2 + this.data.fontSize / 2)
      this.triggerEvent('countReset')
    }

  }
})

演示代码

导入创建的自定义组件

countDownDemo.json

{
  "usingComponents": {
    "count-down":"/components/countDown/countDown"
  }
}

countDownDemo.wxml

<!--pages/countDownDemo/countDownDemo.wxml-->
<view class="container">
  <text>countDownDemo演示</text>
  <view class="count-down-wrapper">
    <count-down id="count-demo" fontColor="#fff" fontSize="20" total="15" width="200rpx" height="200rpx" bind:countEnd="countOver" bind:countPause="countStopCallback" bind:countReset="countResetCallback" />
  </view>
  <view wx:if="{{isEnd}}" class="cout-end-notice">
    <text>倒计时结束了</text>
  </view>
  <view wx:else class="cout-end-notice">
  
  </view>
  <view class="btns">
    <button bind:tap="beginCount" style="width: 30%;">开始</button>
    <button bind:tap="stopCount" style="width: 30%;">暂停</button>
    <button bind:tap="resetCount" style="width: 30%;">重置</button>
  </view>
</view>

countDownDemo.js

// pages/countDownDemo/countDownDemo.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    isEnd: false
  },
  countOver() {
    this.setData({
      isEnd: true
    })
  },
  beginCount() {
    const coutDownRef = this.selectComponent('#count-demo')
    coutDownRef.start()
  },
  stopCount(){
    const coutDownRef = this.selectComponent('#count-demo')
    coutDownRef.pause()
  },
  resetCount(){
    const coutDownRef = this.selectComponent('#count-demo')
    coutDownRef.reset()
    this.setData({
      isEnd:false
    })
  },
  countStopCallback(){
    console.log('count-down触发了暂停')
  },
  countResetCallback(){
    console.log('count-down触发了重置')
  }


})

组件文档

组件prop

参数 说明 类型 默认值
total 倒计时时长,单位秒 number 10
fontSize 倒计时字体大小 number 16 (单位px)
fontColor 字体颜色 string #000
width canvas宽 string 100rpx
height canvas高 string 100rpx

组件events

事件名 说明 回调参数
bind:countPause 倒计时终止时触发
bind:countEnd 倒计时结束时触发
bind:countReset 倒计时重置时触发

组件调用方法

使用selectComponent可以获取到 CountDown 实例并调用实例方法。

方法名 参数 返回值 介绍
start - - 开始倒计时
pause - - 暂停倒计时
reset - - 重设倒计时

示例代码

 const coutDownRef = this.selectComponent('#count-demo') //获取组件示例
 coutDownRef.start()//调用组件开始方法
最后一次编辑于  1天前  
点赞 0
收藏
评论
登录 后发表内容