vue3 实现转盘抽奖

14 篇文章 1 订阅

项目演示
github地址
gitee地址

在这里插入图片描述

调佣代码

<template>
    <div class="content minHeight100">
        <div style="width:300px;margin:50px auto">
            <div class="flex margin-bottom-2x">
                <h4 class="red margin-right-1x">剩余抽奖次数:{{ num }}</h4>
                <button class="color-btn bg-cyan anim-but-5-cyan" @click="startRotation">抽奖</button>
            </div>
       
            <div class="turntableBox">
                <img  src="../../assets/images/Pointer.png"
                    class="RoundTurntableImg" alt="">
                <RoundTurntable ref="roundTurntable" :prizeData="prizeData" :rotateCircle="rotateCircle"
                    :duringTime="duringTime" :turntableStyleOption="turntableStyleOption" @endRotation="endRotation"
                    class="turntable">
                    <template #item="scope">
                        <div class="turntable-name">{{ scope.item.level }}</div>
                        <div class="turntable-img">
                            <img :src="scope.item.picture" />
                        </div>
                    </template>
                </RoundTurntable>
            </div>
        
        </div>
    </div>
</template>

<script>
    import RoundTurntable from '@/view/luckDraw/RoundTurntable';
    import {message} from "ant-design-vue"
    export default {
        name: 'lattice',
        components: {
            RoundTurntable
        },
        data() {
            return {
                // 转盘上的奖品数据
                prizeData: [{
                        id: 1,
                        level: '2000元京东券',
                        picture: require('../../assets/images/gift.png')
                    },
                    {
                        id: 2,
                        level: '300元京东券',
                        picture: require('../../assets/images/gift.png')
                    },
                    {
                        id: 3,
                        level: '加班一天',
                        picture: require('../../assets/images/gift.png')
                    },
                    {
                        id: 4,
                        level: '50元话费券',
                        picture: require('../../assets/images/gift.png')
                    },
                    {
                        id: 5,
                        level: '100元话费券',
                        picture: require('../../assets/images/gift.png')
                    },
                    {
                        id: 6,
                        level: '50元现金',
                        picture: require('../../assets/images/gift.png')
                    },
                    {
                        id: 7,
                        level: '50元现金',
                        picture: require('../../assets/images/gift.png')
                    },
                    {
                        id: 8,
                        level: '50元现金',
                        picture: require('../../assets/images/gift.png')
                    }
                ],
                // 转动的圈数
                rotateCircle: 6,
                // 转动需要持续的时间(s)
                duringTime: 4.5,
                // 转盘样式的选项
                turntableStyleOption: {
                    // 背景色
                    prizeBgColors: ['#ffe0d6', '#fffdfe', '#ffe0d6', '#fffdfe', '#ffe0d6', '#fffdfe', '#ffe0d6',
                        '#fffdfe'
                    ],
                    // 转盘的外边框颜色
                    borderColor: '#fede87'
                },
                // 中奖的奖品的index
                prizeIndex: -1,
                // 用来锁定转盘,避免同时多次点击转动
                isLocking: false,
                // 剩余抽奖次数
                num: 5
            };
        },
        methods: {
            // 开始抽奖
            startRotation() {
                // 如果还不可以转动
                if (!this.canBeRotated()) {
                    return false;
                }
                // 开始转动
                // 先上锁
                this.isLocking = true;
                // 设置在哪里停下,应该与后台交互,这里随机抽取0~5
                const index = Math.floor(Math.random() * this.prizeData.length);
                // 成功后次数减少一次
                this.num--;
                this.prizeIndex = index;
                // 告诉子组件,开始转动了
                this.$refs.roundTurntable.rotate(index);
            },
            // 已经转动完转盘触发的函数
            endRotation() {
                // 提示中奖
                message.success(`恭喜您获奖啦,您的奖品是;${this.prizeData[this.prizeIndex].level}`);
                // 解锁
                this.isLocking = false;
            },
            // 判断是否可以转动
            canBeRotated() {
                if (this.num <= 0) {
                  alert('已经木有次数啦!');
                  return false;
                }
                if (this.isLocking) {
                    return false;
                }
                return true;
            }
        }
    };
</script>

<style lang="scss">
    .turntableBox {
        position: relative;
        width: 300px;
        height: 300px;
        .RoundTurntableImg {
            width: 50px;
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            z-index: 10;
            cursor: pointer;
        }
    }

    .turntable {
        position: absolute;
        //   left: calc(50% - 145px);
        //   top: calc(50% - -10px);
        width: 300px;
        height: 300px;
    }

    .turntable-name {
        /*background: pink;*/
        position: absolute;
        left: 10px;
        top: 20px;
        width: calc(100% - 20px);
        font-size: 14px;
        text-align: center;
        //   color: #fff;
        color: aqua;
    }

    .turntable-img {
        position: relative;
        /*要居中就要50% - 宽度 / 2*/
        left: calc(70% - 100px / 2);
        top: 40px;
        width: 60px;
        height: 60px;

        img {
            display: inline-block;
            width: 60%;
            height: 60%;
        }
    }

</style>
</style>

@/view/luckDraw/RoundTurntable 代码

<template>
  <div class="turntable" ref="turntable">
      <div class="myTurntable" :style="{transform: rotateAngle, transition: rotateTransition}">
        <canvas id="canvas" ref="canvas">
          当前浏览器版本过低,请使用其他浏览器尝试
        </canvas>
        <div>
          
        </div>
        <div class="prize-container">
          <div v-for="(item, index) in prizeData" :key="index" class="item" :style="getRotateAngle(index)">
            <slot name="item" :item="item"></slot>
          </div>
        </div>
      </div>
    </div>


</template>

<script>
  export default {
    name: 'round-turntable',
    mounted() {
      this.init();
    },
    props: {
      prizeData: {
        required: true
      },
      rotateCircle: {
        default: 6
      },
      turntableStyleOption: {
        default: () => {
          return {
            // 背景色
            prizeBgColors: ['#ffdfd4', '#fffdfe', '#ffdfd4', '#fffdfe', '#ffdfd4', '#fffdfe', '#ffdfd4', '#fffdfe'],
            // 转盘的外边框颜色
            borderColor: '#f9dc84'
          };
        }
      },
      duringTime: {
        default: 4.5
      }
    },
    data() {
      return {
        // 开始转动的角度
        startRotateDegree: 0,
        rotateAngle: 0,
        rotateTransition: ''
      };
    },
    methods: {
      // 根据index计算每一格要旋转的角度的样式
      getRotateAngle(index) {
        const angle = 360 / this.prizeData.length * index + (180 / this.prizeData.length);
        return {
          transform: `rotate(${angle}deg)`
        };
      },
      // 初始化圆形转盘canvas
      init() {
        // 各种数据
        const data = this.turntableStyleOption;
        const prizeNum = this.prizeData.length;
        const {
          prizeBgColors,
          borderColor
        } = data;
        // 开始绘画
        const canvas = this.$refs.canvas;
        const ctx = canvas.getContext('2d');
        const canvasW = this.$refs.canvas.width = this.$refs.turntable.clientWidth; // 画板的高度
        const canvasH = this.$refs.canvas.height = this.$refs.turntable.clientHeight; // 画板的宽度
        // translate方法重新映射画布上的 (0,0) 位置
        ctx.translate(0, canvasH);
        // rotate方法旋转当前的绘图,因为文字适合当前扇形中心线垂直的!
        ctx.rotate(-90 * Math.PI / 180);
        // 圆环的外圆的半径
        const outRadius = canvasW / 2;
        // 圆环的内圆的半径
        const innerRadius = 0;
        const baseAngle = Math.PI * 2 / prizeNum; // 计算每个奖项所占角度数
        ctx.clearRect(0, 0, canvasW, canvasH); // 去掉背景默认的黑色
        ctx.strokeStyle = borderColor; // 设置画图线的颜色
        for (let index = 0; index < prizeNum; index++) {
          const angle = index * baseAngle;
          ctx.fillStyle = prizeBgColors[index]; // 设置每个扇形区域的颜色
          ctx.beginPath(); // 开始绘制
          // 标准圆弧:arc(x,y,radius,startAngle,endAngle,anticlockwise)
          ctx.arc(canvasW * 0.5, canvasH * 0.5, outRadius, angle, angle + baseAngle, false);
          ctx.arc(canvasW * 0.5, canvasH * 0.5, innerRadius, angle + baseAngle, angle, true);
          ctx.stroke(); // 开始链线
          ctx.fill(); // 填充颜色
          ctx.save(); // 保存当前环境的状态
        }
      },
      // 转动起来
      rotate(index) {
        // 运转时长
        const duringTime = this.duringTime;
        const rotateAngle = this.startRotateDegree + this.rotateCircle * 360 + 360 - (180 / this.prizeData.length +
          360 / this.prizeData.length * index) - this.startRotateDegree % 360;
        this.startRotateDegree = rotateAngle;
        this.rotateAngle = `rotate(${rotateAngle}deg)`;
        this.rotateTransition = `transform ${duringTime}s cubic-bezier(0.250, 0.460, 0.455, 0.995)`;
        setTimeout(() => {
          this.$emit('endRotation');
        }, duringTime * 1000 + 500);
      }
    }
  };
</script>

<style scoped lang="scss">

  

  .turntable {
    .myTurntable {
      position: absolute;
      left: 0;
      top: 0;
      width: 100%;
      height: 100%;
    }

    .prize-container {
      position: absolute;
      left: 25%;
      top: 0;
      width: 50%;
      height: 50%;

      .item {
        /*background: pink;*/
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        height: 100%;
        transform-origin: center bottom;
      }
    }
  }
</style>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值