抽奖轮盘组件的封装

439 阅读1分钟

最近公司要做一个抽奖的活动。由于时间关系我使用的是同事的组件。但是活动过后心里难免心生内疚,毕竟如果老是使用别人封装好的东西也挺不好意思的。所以我打算自己封装一个抽奖的组件Demo来为我以后写这类活动提供思路。

话不多说,直接上代码吧。

lottory.vue

<template>
  <div class="lottory">
   <div class="lottory-wrap relative">
    <div v-for="(item,index) in items" :key="index" class="lottory-item absolute" :class="item.isActive ? 'isActive' : ''" :style="item.position">{{item.id}}</div>
    <div class="lottory-btn absolute" @click="onStartLottory(steps)">抽奖</div>
   </div>
  </div>
</template>

<script>

let $activeIndex = 0 //记录当前轮盘停留的位置
let $count = 0 // 定义一个变量来判断是否走完了传入的步数
let $lottorying = false // 定义这个变量判断是否还在抽奖中以防止多次点击

export default {
 name: 'lottory',
  props: {
    items: {
      type: Array,
      default: () => []
    },
    steps: {
      type: Number,
      default: () => 0
    }
  },
  methods: {
    onStartLottory(steps) {
      if(!steps) {
        return
      }

      if($lottorying) {
        console.log('正在抽奖')
        return
      }

      $lottorying = true

      const timer = setInterval(() => {
        if($activeIndex === 8) {
          $activeIndex = 0
        }

        this.items.forEach((item, index) => {
          if($activeIndex === index) {
            this.$set(item, 'isActive', true)
          } else {
            this.$set(item, 'isActive', false)
          }
        })

        if($count === steps) {
          $count = 0
          $lottorying = false
          clearInterval(timer)
          return
        }

        $activeIndex++
        $count++
      }, 100)
    }
  }
}
</script>

<style>
.relative {
  position: relative;
}
.absolute {
  position: absolute;
}
.lottory-item {
  width: 50px;
  height: 50px;
  background: red;
  line-height: 50px;
  text-align: center;
  color: #fff;
}
.lottory-btn {
  width: 50px;
  height: 50px;
  left: 60px;
  top: 60px;
  background: blue;
  color: #fff;
  font-weight: 600;
  font-size: 20px;
  text-align: center;
  line-height: 50px;
}
.isActive{
  background: #39b89c;
}
</style>

app.vue

<template>
  <div id="app">
    <lottory :items.sync="items" :steps="steps" ref="my-lottory"></lottory>
    <div class="start-btn" @click="start(10)"></div>
  </div>
</template>

<script>
import lottory from './components/lottory.vue'

export default {
  name: 'App',
  components: {
    lottory
  },
  data() {
    return {
      items : [
        {id:1, position: {}},
        {id:2, position: {left:'60px',top:'0'}},
        {id:3, position: {left:'120px', top:'0'}},
        {id:4, position: {left:'120px',top:'60px'}},
        {id:5, position: {left:'120px',top:'120px'}},
        {id:6, position: {left:'60px',top:'120px'}},
        {id:7, position: {left:'0',top:'120px'}},
        {id:8, position: {left:'0',top:'60px'}}
      ],
      steps: 0
    }
  },
  methods: {
    start(steps) {
      this.$refs['my-lottory'].onStartLottory(steps)
    }
  }
}
</script>

<style>
.start-btn{
  position: absolute;
  width: 50px;
  height: 50px;
  top: 67px;
  left: 67px;
}
</style>

最后的效果图

rxkdk-y3qya.gif

之后的一些改进的想法

公司做的活动大部分都是需要贴图的,然而我做的这个组件只是将功能实现了,然后样式方面没有做很好的封装。后续我会尝试将暂时写死的样式换成可传入图片的形式。