小程序 Canvas 倒计时组件 (React 版)

基于前面Web版修改而来    Canvas 倒计时

 源码:

 

import { Canvas, View } from "@tarojs/components"
import Taro from '@tarojs/taro'
import { FC } from "@tarojs/taro"
import rpxToPx from "../../utils/dom"
import { useEffect, useState } from "react"
import './countDown.less'
import React from "react"

interface ICountDownProps {
    onMissed: () => void
    duration: number // 总时长
    countTime: number // 已经错过的时间
}

let timer
const CountDown: FC<ICountDownProps> = ({ onMissed, duration, countTime }) => {

    const basePx = 280
    const [time] = useState(duration) // 可以随意设置
    let [count, setCount] = useState(duration - countTime) // 倒计时剩余时间
    const percent = 2 / time // 每一秒需要的度数

    useEffect(() => {
        Taro.eventCenter.on('onSignClose', () => {
            clearInterval(timer)
        })

        return () => {
            clearInterval(timer)
            Taro.eventCenter.off('onSignClose')
        }
    }, [])

    const XYPoint = rpxToPx(basePx) / 2
    const R = (rpxToPx(basePx) - 7) / 2

    const getPercent = (count) => {
        const deg = (time - count) * percent
        console.log('count , deg:', count, deg)
        return deg <= 0 ? -0.5 * Math.PI : (1.5 - deg) * Math.PI
    }

    const drawBottom = () => {
        wx.createSelectorQuery()
            .select('#cvs1')
            .fields({
                node: true,
                size: true,
            })
            .exec((res) => {
                console.log(res)
                if (!res[0]) return
                const canvas = res[0].node
                const ctx1 = canvas.getContext('2d')

                // 设置canvas 高宽
                const dpr = wx.getSystemInfoSync().pixelRatio
                canvas.width = rpxToPx(basePx) * dpr
                canvas.height = rpxToPx(basePx) * dpr
                ctx1.scale(dpr, dpr)

                ctx1.beginPath()
                ctx1.lineWidth = 3
                ctx1.strokeStyle = '#d9d9d9'
                ctx1.arc(XYPoint, XYPoint, R, 0, 2 * Math.PI, false)
                ctx1.stroke()
            })
    }

    const drawCenter = () => {
        wx.createSelectorQuery()
            .select('#cvs2')
            .fields({
                node: true,
                size: true,
            })
            .exec((res) => {
                console.log(res)
                if (!res[0]) return
                const canvas = res[0].node
                const ctx2 = canvas.getContext('2d')

                // 设置canvas 高宽
                const dpr = wx.getSystemInfoSync().pixelRatio
                canvas.width = rpxToPx(basePx) * dpr
                canvas.height = rpxToPx(basePx) * dpr
                ctx2.scale(dpr, dpr)

                ctx2.beginPath()
                ctx2.lineWidth = 5
                ctx2.strokeStyle = '#4F8BFF'
                ctx2.lineCap = 'round'
                ctx2.arc(XYPoint, XYPoint, R, 1.5 * Math.PI, getPercent(count), false)
                ctx2.stroke()
            })
    }

    const drawTop = () => {
        wx.createSelectorQuery()
            .select('#cvs3')
            .fields({
                node: true,
                size: true,
            })
            .exec((res) => {
                console.log(res)
                if (!res[0]) return
                const canvas = res[0].node
                const ctx3 = canvas.getContext('2d')

                // 设置canvas 高宽
                const dpr = wx.getSystemInfoSync().pixelRatio
                canvas.width = rpxToPx(basePx) * dpr
                canvas.height = rpxToPx(basePx) * dpr
                ctx3.scale(dpr, dpr)

                ctx3.beginPath()
                ctx3.lineWidth = 5
                ctx3.strokeStyle = '#4F8BFF'
                ctx3.lineCap = 'round'
                ctx3.arc(XYPoint, XYPoint, R, 1.5 * Math.PI, getPercent(count), false)
                ctx3.stroke()
            })
    }

    const startCountDown = () => {
        if (count <= 1) {
            onMissed()
            clearInterval(timer)
            return
        }
        setCount(--count)
        wx.createSelectorQuery()
            .select('#cvs2')
            .fields({
                node: true,
                size: true,
            })
            .exec((res) => {
                console.log(res)
                if (!res[0]) return
                const canvas = res[0].node
                const ctx2 = canvas.getContext('2d')

                // 设置canvas 高宽
                const dpr = wx.getSystemInfoSync().pixelRatio
                canvas.width = 0
                canvas.width = rpxToPx(basePx) * dpr
                canvas.height = rpxToPx(basePx) * dpr
                ctx2.scale(dpr, dpr)
            })


        setTimeout(() => {
            drawCenter()

            wx.createSelectorQuery()
                .select('#cvs3')
                .fields({
                    node: true,
                    size: true,
                })
                .exec((res) => {
                    console.log(res)
                    if (!res[0]) return
                    const canvas = res[0].node
                    const ctx3 = canvas.getContext('2d')

                    // 设置canvas 高宽
                    const dpr = wx.getSystemInfoSync().pixelRatio
                    canvas.width = 0
                    canvas.width = rpxToPx(basePx) * dpr
                    canvas.height = rpxToPx(basePx) * dpr
                    ctx3.scale(dpr, dpr)
                })

            setTimeout(() => {
                drawTop()
            }, 20)
        }, 20)
    }

    useEffect(() => {
        setTimeout(() => {
            drawBottom()
            drawCenter()
            drawTop()
        }, 100)

        timer = setInterval(startCountDown, 1000)
    }, [])

    const _pixel = rpxToPx(basePx)

    return <View
        style={`width: ${_pixel}px; height: ${_pixel}px;`}
        className="countdown-container flex flex-item-center flex-justify-center">
        <Canvas style={`width: ${_pixel}px; height: ${_pixel}px;z-index: 0;`} id="cvs1" type="2d"></Canvas>
        <Canvas style={`width: ${_pixel}px; height: ${_pixel}px;z-index: 1;`} id="cvs2" type="2d"></Canvas>
        <Canvas style={`width: ${_pixel}px; height: ${_pixel}px;z-index: 2;`} id="cvs3" type="2d"></Canvas>
        <View className="flex flex-col flex-justify-center flex-item-center">
            <View className="timer-count flex flex-item-center flex-justify-center"> {count} </View>
            <View className="timer-tips flex flex-item-center" > 倒计时 (S) </View>
        </View>
    </View >
}

export default CountDown

  

 

rpx to px(横屏、分辨率适配需要用到):

export default function rpxToPx(rpx) {
    const orientation = wx.getSystemInfoSync().deviceOrientation
    if (orientation == 'landscape') {
        return Math.round(rpx * wx.getSystemInfoSync().windowHeight / 750)
    }

    return Math.round(rpx * wx.getSystemInfoSync().windowWidth / 750)
}

  

 

效果:

  

 

posted @ 2021-07-15 11:03  序猿·徐  阅读(155)  评论(0编辑  收藏  举报