前端vue大转盘抽奖

376 阅读2分钟

功能介绍

因为是移动端转盘抽奖所以使用了upx单位。

  1. 支持展示文字
  2. 支持显示图片
  3. 支持后端指定抽奖结果
  4. 可自定义轮盘宽度,背景颜色,按钮/指针图片

效果展示

WX20240607-112745.png

源码

<template>
  <view class="page">
    <view class="Alottery">
      <view class="AlotteryMain">
        <view class="graph-page">
          <view class="plate-wrapper" :style="`${bgColor};`">
            <view class="item-plate" :style="plateCss(index)" v-for="(item, index) in plateList" :key="index">
              <p>{{ item.prizeName }}</p>
              <img :src="item.prizeImg" alt="" />
            </view>
          </view>
          <view @click="extract" class="btn"></view>
        </view>
      </view>
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      plateList: [], //奖品列表
      isRunning: false, //判断是否正在转动
      rotateAngle: 0, //转盘每项角度
      baseRunAngle: 360 * 5, //总共转动角度,至少5圈
      totalRunAngle: 0, //要旋转的总角度
      activeIndex: 0, //中奖index
      wrapDom: null //转盘dom
    };
  },
  computed: {
    bgColor() {
      //转盘的每项背景
      let len = this.plateList.length;
      let color = ['#fda403', '#f33535'];
      let colorVal = '';
      this.plateList &&
        this.plateList.forEach((item, index) => {
          colorVal += `${color[index % 2]} ${(360 / len) * index}deg ${(360 / len) * (index + 1)}deg,`;
        });
      return `background: conic-gradient(${colorVal.slice(0, -1)})`;
    },
    plateCss() {
      //转盘的每项样式
      if (this.plateList && this.plateList.length) {
        return i => {
          return `
				  width: ${Math.floor(2 * 485 * Math.sin(((this.rotateAngle / 2) * Math.PI) / 180))}upx;
				  height: 600upx;
				  transform: rotate(${this.rotateAngle * i + this.rotateAngle / 2}deg);
				  transform-origin: 50% 100%;
				`;
        };
      }
      return () => {
        '';
      };
    }
  },
  created() {
    this.getPrizeList(); // 模拟请求奖品列表接口
  },
  mounted() {
    this.$nextTick(() => {
      this.wrapDom = document.getElementsByClassName('plate-wrapper')[0];
    });
  },
  beforeDestroy() {
    this.wrapDom.removeEventListener('transitionend', this.stopRun);
  },

  methods: {
    // 模拟获取奖品列表接口
    getPrizeList() {
      let testing = [
        {
          id: '1',
          prizeImg: 'https://img.ixintu.com/upload/jpg/20210612/4bd6a895253f0fd0dea87a3db22ccb9f_177837_800_1640.jpg!con0',
          prizeName: '棒棒糖1'
        },
        {
          id: '2',
          prizeImg: 'https://img.ixintu.com/upload/jpg/20210612/4bd6a895253f0fd0dea87a3db22ccb9f_177837_800_1640.jpg!con0',
          prizeName: '棒棒糖2'
        },
        {
          id: '3',
          prizeImg: 'https://img.ixintu.com/upload/jpg/20210612/4bd6a895253f0fd0dea87a3db22ccb9f_177837_800_1640.jpg!con0',
          prizeName: '棒棒糖3'
        },
        {
          id: '4',
          prizeImg: 'https://img.ixintu.com/upload/jpg/20210612/4bd6a895253f0fd0dea87a3db22ccb9f_177837_800_1640.jpg!con0',
          prizeName: '棒棒糖4'
        },
        {
          id: '5',
          prizeImg: 'https://img.ixintu.com/upload/jpg/20210612/4bd6a895253f0fd0dea87a3db22ccb9f_177837_800_1640.jpg!con0',
          prizeName: '棒棒糖5'
        },
        {
          id: '6',
          prizeImg: 'https://img.ixintu.com/upload/jpg/20210612/4bd6a895253f0fd0dea87a3db22ccb9f_177837_800_1640.jpg!con0',
          prizeName: '棒棒糖6'
        },
        {
          id: '7',
          prizeImg: 'https://img.ixintu.com/upload/jpg/20210612/4bd6a895253f0fd0dea87a3db22ccb9f_177837_800_1640.jpg!con0',
          prizeName: '棒棒糖7'
        },
        {
          id: '8',
          prizeImg: 'https://img.ixintu.com/upload/jpg/20210612/4bd6a895253f0fd0dea87a3db22ccb9f_177837_800_1640.jpg!con0',
          prizeName: '棒棒糖8'
        }
      ];
      this.plateList = testing;//奖品赋值

      //   根据奖品数量绘制扇形
      this.rotateAngle = 360 / this.plateList.length;
      this.totalRunAngle = this.baseRunAngle + 360 - this.activeIndex * this.rotateAngle - this.rotateAngle / 2;
    },

    // 1点击抽奖按钮
    extract() {
      if (this.isRunning) return;
      this.isRunning = true;
      this.drawFu();
    },
    // 2抽奖
    drawFu() {
      this.activeIndex = 1; //控制抽奖奖品下标
      this.rotateAngle = 360 / this.plateList.length;
      this.totalRunAngle = this.baseRunAngle + 360 - this.activeIndex * this.rotateAngle - this.rotateAngle / 2;
      this.startRun();
    },
    // 3转动
    startRun() {
      this.wrapDom.setAttribute(
        'style',
        `
		${this.bgColor};
		transform: rotate(${this.totalRunAngle}deg);
		transition: all 4s ease;
		`
      );
      this.wrapDom.addEventListener('transitionend', this.stopRun); // 监听transition动画停止事件
    },
    // 4抽奖停止
    stopRun() {
      this.isRunning = false;
      this.wrapDom.setAttribute(
        'style',
        `
			  ${this.bgColor};
			  transform: rotate(${this.totalRunAngle - this.baseRunAngle}deg);
			`
      );
    }
  }
};
</script>

<style lang="scss" scoped>
.page {
  width: 100vw;
  height: 100vh;
  background-color: #fff;
  display: flex;
  justify-content: center;

  /* 圆盘 */
  .Alottery {
    width: 630upx;
    height: 630upx;
    background-color: #f9d76c;
    border-radius: 50%;
    display: flex;
    justify-content: center;
    align-items: center;

    .title {
      text-align: center;
      color: #fff;
      font-size: 32px;
      line-height: 4rem;
    }
    .AlotteryMain {
      width: 100%;
      height: 600upx;
      display: flex;
      justify-content: center;
      align-items: center;

      .graph-page {
        width: 1200upx;
        height: 1200upx;
        transform: scale(0.5);
      }
      .plate-wrapper {
        width: 1200upx;
        height: 1200upx;
        border-radius: 50%;
      }
      .item-plate {
        margin: auto;
        box-sizing: border-box;
        position: absolute;
        top: 0upx;
        left: 0upx;
        right: 0upx;
      }
      .item-plate img {
        width: 135upx;
        height: 135upx;
        margin-top: 30upx;
        margin: auto;
        display: block;
        padding: 10upx;
        box-sizing: border-box;
      }
      .item-plate p {
        width: 100%;
        height: 75upx;
        color: #fff;
        font-size: 22px;
        text-align: center;
        line-height: 22px;
        margin-top: 60upx;
        padding: 0 20upx;
        box-sizing: border-box;
      }
      .btn {
        width: 160px;
        height: 160px;
        background: url('https://www.jq22.com/demo/jquerylocal201912122316/img/btn_lottery.png') no-repeat center / 100% 100%;
        position: absolute;
        left: 0;
        right: 0;
        top: 0;
        bottom: 0;
        margin: auto;
        cursor: pointer;
      }
      .btn::before {
        content: '';
        width: 41px;
        height: 39px;
        background: url('https://www.jq22.com/demo/jquerylocal201912122316/img/icon_point.png') no-repeat center / 100% 100%;
        position: absolute;
        left: 0;
        right: 0;
        top: -33px;
        margin: auto;
      }
    }
  }
}
</style>