vue中实现大转盘抽奖

Posted 铁锤妹妹@

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue中实现大转盘抽奖相关的知识,希望对你有一定的参考价值。

官方文档入口

一. 在 Vue 中使用

  1. 安装插件
npm install vue-luck-draw
  1. 找到 main.js 全局引入插件并 use,或者在组件中按需引入插件。
// 按需引入
import { LuckyWheel } from 'vue-luck-draw'
Vue.components('LuckyWheel', LuckyWheel)
  1. 最后在页面内使用 <LuckyWheel />大转盘组件,根据官方文档想要的配置参数

二. 转盘抽奖正常流程

1. 当你点击抽奖按钮时触发strat回调函数,接下来你可以调用play()方法先让大转盘转起来,然后紧接着去请求接口拿数据,或是你自己随机一个index
2. 当接口拿到index中奖索引之后,你就可以调用stop(index)方法了,此时大转盘会缓慢停止,当完全停止之后就会触发end回调函数(当接口返回的速度很快的时候,会跳过匀速阶段,此时可手动加一个定时器延缓调用的时机)
3. 最后在end回调函数里面,得到中奖奖品的全部信息,你就可以在这里执行逻辑告诉用户他中奖了

代码如下:

<template>
  <div class="wrap">
    <div class="lucky_wheel">
      <img
        class="lucky_title"
        src="../../assets/image/luckly/written words.png"
      />
      <div class="wheel_main">
        <LuckyWheel
          class="role"
          ref="LuckyWheel"
          width="6.48rem"
          height="6.48rem"
          :prizes="prizes"
          :buttons="buttons"
          :default-style="defaultStyle"
          @start="startCallBack"
          @end="endCallBack"
        />
        <div class="count_info">
          还可抽奖<span class="count">{{ count }}</span>
        </div>
      </div>
    </div>
    <div class="tip_con">
      <img
        class="tip_btn"
        src="../../assets/image/luckly/activity details.png"
      />
      <div class="tip_content">
        <div class="tip_item">
          <div class="img_num">
            <span class="number">1</span>
          </div>
          <p>
            活动细则活动细则活动细则活动细则活动细则活动细则活动细则活动细则
          </p>
        </div>
        <div class="tip_item">
          <div class="img_num">
            <span class="number">2</span>
          </div>
          <p>
            活动细则活动细则活动细则活动细则活动细则活动细则活动细则活动细则
          </p>
        </div>
      </div>
      <img class="logo" src="../../assets/image/luckly/luckly-logo.png" />
      <van-overlay :show="verifyDialogShow">
        <div class="overlayMain">
          <div class="overlay_title">中奖信息</div>
          <div class="info">
            {{ overlayInfo }}
          </div>
          <div class="confirm" @click="confirm">确认</div>
        </div>
      </van-overlay>
    </div>
  </div>
</template>

<script>
import { LuckyWheel } from "vue-luck-draw";
import { Overlay } from "vant";
export default {
  data() {
    return {
      prizes: [],
      buttons: [
        {
          radius: "30%",
          imgs: [
            {
              src: require("../../assets/image/luckly/luckly_btn.png"),
              width: "200%",
              top: "-185%"
            }
          ]
        }
      ],
      defaultStyle: {
        fontSize: "10px",
        fontColor: "#EC652D"
      },
      verifyDialogShow: false,
      count: 0, // 剩余抽奖次数
      winId: "", //获取奖品的id
      winName: "", //中奖奖品名字
      mid: 999,
      currentIndex: 0 //抽中数组中第几个奖品
    };
  },
  computed: {
    overlayInfo() {
      return this.winId > 0 ? `恭喜你获得${this.winName}` : "谢谢参与";
    }
  },
  created() {
    this.getPrizesList();
  },
  methods: {
    getPrizesList() {
      let data = [
        {
          id: "12",
          name: "奖品1",
          image: require("../../assets/image/luckly/doubledouzi.png")
        },
        {
          id: "24",
          name: "奖品2",
          image: require("../../assets/image/luckly/douzi.png")
        },
        {
          id: "3",
          name: "奖品3",
          image: require("../../assets/image/luckly/pinggai.png")
        },
        {
          id: "14",
          name: "奖品4",
          image: require("../../assets/image/luckly/double_pinggai.png")
        },
        {
          id: "5",
          name: "奖品5",
          image: require("../../assets/image/luckly/qiandai.png")
        },
        {
          id: "6",
          name: "奖品6",
          image: require("../../assets/image/luckly/qiandai.png")
        }
      ];
      this.dataList = data;
      this.count = 2;
      var thanks_obj = {
        id: "0",
        name: "谢谢参与",
        image: require("../../assets/image/luckly/thank.png")
      };
      if (this.dataList.length % 2 == 1) {
        //如果数组是奇数的话,直接在数组最前面添加谢谢参与,为了转盘背景颜色是间隔的
        this.dataList.unshift(thanks_obj);
      } else {
        //如果数组是偶数的话,在数组最前面和数组中间添加谢谢参与
        this.mid = this.dataList.length / 2;
        this.dataList.splice(this.mid, 0, thanks_obj);
        this.dataList.unshift(thanks_obj);
      }
      console.log(this.dataList);
      this.dataList.forEach((item, index) => {
        this.prizes.push({
          name: item.name,
          background: index % 2 ? "#FFD787" : "#fff",
          fonts: [
            {
              text: item.name,
              top: "10px"
            }
          ],
          imgs: [
            {
              src: item.image,
              width: "35px",
              // top: "30px",
              // width: "25%",
              top: "30%"
            }
          ]
        });
      });
    },
    startCallBack() {
      //没有抽奖次数return出去
      if (this.count == 0) {
        this.$toast("没有抽奖次数了");
        return;
      }
      this.count--;
      this.$refs.LuckyWheel.play();

      this.winId = parseInt("5"); //模拟接口,这里转换为number类型
      //留出匀速的时间
      setTimeout(() => {
        if (this.winId == 0) {
          this.$refs.LuckyWheel.stop(0); //如果winId=0,直接取数组里的第一个
        } else {
          this.dataList.forEach((item, index) => {
            //否则循环数组,拿中奖奖品id去数组里item.id比对,如果两个id值相等的话,就取数组当前的索引,赋值给 this.currentIndex
            if (item.id == this.winId) {
              this.currentIndex = index;
              console.log(index);
            }
          });
          this.$refs.LuckyWheel.stop(this.currentIndex);
          //一开始用的下面这种取索引方法,发现不行,因为当时想象的是id从1开始,依次排列。但是在真正项目中,id会打乱
          //如果是数组长度是奇数的话走if,偶数的话多加了两个谢谢参与,中间谢谢参与之前的索引走if;之后的索引取值走else
          // if (this.winId <= this.mid) {  
          //   this.$refs.LuckyWheel.stop(this.winId);
          // } else {
          //   this.$refs.LuckyWheel.stop(this.winId + 1);
          // }
        }
      }, 3000);
    },
    endCallBack(prize) {
      this.winName = prize.name;
      this.verifyDialogShow = true;
    },

    confirm() {
      this.verifyDialogShow = false;
    }
  },
  components: {
    VanOverlay: Overlay,
    LuckyWheel: LuckyWheel
  }
};
</script>

<style lang="scss" scoped>
.lucky_wheel {
  height: 572px;
  background: url("../../assets/image/luckly/background_2.png") no-repeat;
  background-size: cover;
  .lucky_title {
    width: 312px;
    margin: 0 auto;
    padding-top: 13px;
  }
  .wheel_main {
    position: relative;
    background: url("../../assets/image/luckly/turntable.png") no-repeat;
    background-size: cover;
    width: 345px;
    height: 399px;
    margin: -8px auto;
    .role {
      // width: 243px;
      // height: 243px;
      // border-radius: 500px;
      position: absolute;
      top: 50px;
      left: 51px;
      // overflow: hidden;
    }
    .count_info {
      position: absolute;
      bottom: 14px;
      left: 50%;
      transform: translateX(-50%);
      color: #fff;
      text-align: center;
      margin-top: -30px;
      letter-spacing: 3px;
      font-size: 12px;
      .count {
        color: #ffc47c;
        font-weight: bold;
      }
    }
  }
}
.tip_con {
  height: auto;
  background: url("../../assets/image/luckly/background_3.png") no-repeat;
  background-size: 100% 100%;
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  position: relative;
  .tip_btn {
    position: absolute;
    top: -26px;
    width: 292px;
    height: 59px;
  }
  .tip_content {
    background: url("../../assets/image/luckly/rule_bg.png") no-repeat;
    background-size: 100% 100%;
    width: 344px;
    height: auto;
    padding: 50px 14px 30px 14px;
    box-sizing: border-box;
    border-radius: 5px;
    .tip_item {
      display: flex;
      margin-bottom: 8px;
      .img_num {
        background: url("../../assets/image/luckly/digital.png") no-repeat;
        background-size: cover;
        width: 20px;
        height: 20px;
        display: flex;
        justify-content: center;
        align-items: center;
        margin-right: 5px;
      }
      .number {
        font-size: 13px;
        color: #de192e;
      }
      p {
        flex: 1;
        color: #fcf6ef;
        letter-spacing: 1px;
        line-height: 16px;
        font-size: 12px;
      }
    }
  }
  .logo {
    margin: 25px auto 44px;
    width: 90px;
    height: 21px;
  }
  .overlayMain {
    width: 90%;
    height: auto;
    border-radius: 12px;
    background: #fff;
    position: absolute;
    top: 200px;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    align-items: center;
    flex-direction: column;
    .overlay_title {
      padding-top: 26px;
      font-size: 16px;
      font-weight: bold;
    }
    .info {
      font-size: 14px;
      padding: 8px 24px 26px;
      text-align: center;
    }
    .confirm {
      width: 100%;
      height: 48px;
      line-height: 48px;
      border-top: 1px solid #ebedf0;
      color: #ee0a24;
      font-size: 16px;
      text-align: center;
    }
  }
}
</style>

三. 遇到的bug

1)转盘抽奖这里遇到一个bug,点击指针让转盘转的时候,ios上需要点击两下,安卓上是正常的
排查问题发现是用的vant dialog弹窗组件的问题,更换成Overlay 遮罩层组件问题就解决了

2)

以上是关于vue中实现大转盘抽奖的主要内容,如果未能解决你的问题,请参考以下文章

Vue,React ---大转盘 & 九宫格抽奖

vue进入页面两秒后转盘转动

PHP jQuery微信大转盘抽奖源代码分享

鸿蒙HarMonyOS的自定义组件之抽奖大转盘

PHP jQuery微信大转盘抽奖源代码分享

模仿抽奖转盘,并且用cookie记录历史次数