微信小程序canvas实现抽奖动画

发布于:2025-06-21 ⋅ 阅读:(15) ⋅ 点赞:(0)

本来想用setdata做抽奖动画的,但是存在合并更新以及性能问题,遂采用canvas的形式。

参考了一篇blog,然后加了些抽奖逻辑的改动

<!--components/names/names.wxml-->
<view class="component-names">
  <canvas type="2d" id="myCanvas" style="width: 200px;height: 200px;"></canvas>
</view>
import { getRandomInt } from "../../utils/util";

// components/names/names.ts
Component({
  lifetimes: {
    attached() {
      this.createSelectorQuery().select("#myCanvas").fields({
        node: true,
        size: true
      }).exec(res => this.init(res));
    },
  },
  /**
   * 组件的属性列表
   */
  properties: {
    names: {
      type: Array,
      value: ['小红', '大明', '阿花']
    }
  },

  /**
   * 组件的初始数据
   */
  data: {

  },

  /**
   * 组件的方法列表
   */
  methods: {
    init(res) {
      // console.log('init', res)
      const width = res[0].width
      const height = res[0].height
      // 设置画布宽高
      const canvas = res[0].node
      const ctx = canvas.getContext('2d')
      canvas.width = width
      canvas.height = height
      /** 半径 */
      let rArr = [];
      /** 透明度 */
      let alpha = [];

      const renderLoop = () => {
        /** 最小半径 */
        const circleStartR = width / 2 - 40;
        /** 最大半径 */
        const circleEndR = width / 2 - 8;
        /** 动画时间 */
        let animationTime = 300;
        /** 每次增大的宽度 */
        let speed = (circleEndR - circleStartR) / animationTime;

        rArr = rArr.map(item => item + speed);
        alpha = alpha.map(item => item + 1 / animationTime);
        // 如果数组为空|| 最小圆半径-最小半径>圆间隔
        if (!rArr[0] || rArr[0] - circleStartR > 10) {
          rArr.unshift(circleStartR);
          alpha.unshift(0);
        }

        // 如果最大圆半径>=最大半径
        if (rArr[rArr.length - 1] >= circleEndR) {
          rArr.pop();
        }

        this.render(width, ctx, rArr, alpha)
        canvas.requestAnimationFrame(renderLoop)
      }
      canvas.requestAnimationFrame(renderLoop)
    },
    renderName(width, ctx) {
      const center = width / 2;
      ctx.clearRect(center - 50, center - 50, center, center)
      let name = this.properties.names[getRandomInt(0, this.properties.names.length - 1)];
      let w = ctx.measureText(name).width;
      ctx.fillText(name, center - w / 2, center + 10)
      ctx.font = '30px bold'
    },
    render(width, ctx, rArr, alpha) {
      ctx.clearRect(0, 0, width, width);
      const center = width / 2;
      this.renderName(width, ctx);
      function ball(r, a) {
        // 设置渐变
        let grd = ctx.createLinearGradient(0, 0, 100, 0);
        grd.addColorStop(0, 'rgba(132, 251, 251, ' + a + ')') //渐变颜色的添加
        grd.addColorStop(0.5, 'rgba(118, 133, 254, ' + a + ')');
        grd.addColorStop(1, 'rgba(2545, 4, 255, ' + a + ')');
        ctx.beginPath();
        // 画圆
        ctx.arc(center, center, r, 0, 2 * Math.PI);
        // 描边样式设置
        ctx.strokeStyle = grd;
        ctx.closePath();
        // 描边
        ctx.stroke();
      }
      for (let i = 0; i < rArr.length; i++) {
        let r = rArr[i];
        let a = alpha[i];
        ball(r, a);
      }
    },
  }
})

参考:微信小程序canvas制作动画_微信小程序 canvas动画-CSDN博客


网站公告

今日签到

点亮在社区的每一天
去签到