JS-VUE-九宫格抽奖

6,512 阅读3分钟

前言

继之前两篇“老虎机抽奖”、“大转盘抽奖”,所以把九宫格也一并补全了,整体的实现方案不是很复杂,就是dom以及中奖的配置需要特别注意一下,好了话不多少,直接开始~

其他方案

JS-VUE-老虎机抽奖>>>

JS-VUE-大转盘抽奖>>>

UI

  • 老规矩,先看下静态UI,以便于有个图像概念

1620808806(1).jpg

方案分析

  • 思路清单

    • 结构布局,九个位置(左青龙,右白虎,老牛在中间),具体的可以看下面参考图

      • 这里有个好玩的地方了,1-9个位置(可不是简单的1-9哦,是跑外圈哦),如果是静态布局,其实就是九个盒子,没啥复杂的;但如果是动态渲染同一个数据列表,有同学说了,也很简单做个判断呗;但是如果服务端返回的json是无序的,那么我们要怎么处理前端的方案以及怎么和服务端制定比较友好的数据结构呢,先买个小关子,一起往下看,看看我会不会和可爱的你想的一样呢~
    • 核心逻辑,跑毒(不对跑圈)

        1. 设定数量圈数 (我就是个冷冰冰的数字)
        1. 设置速度(思路就是,每一次递归我都会越来越快哦,好吧,其实就是速度++,等到达上述1的指定圈数后,我在+10圈让速度--,是不是很简单~)
    • 选中效果(不用怜悯我,根据每次递归的下标,给我设置一个冷冰冰的class并把上一个兄弟的class清空就行了)

  • 初始参考各值参考图

abb6e1af3314d0718664561ce8fff92.png

实现逻辑

参数配置

data () {
    return {
      resultList: [], // 奖品列表
      isTurn: true, // 是否可以抽奖
      index: 1, //当前转动到哪个位置,起点位置
      orderList: [1, 2, 3, 8, -9, 4, 7, 6, 5], // 正常循环排列下的顺序 0 为中间的抽奖按钮/分区标识
      lotterywin: -9, // 中奖位置
      lottery: {
        count: 8, //总共有多少个位置
        timer: 0, //setTimeout的ID,用clearTimeout清除
        speed: 35, //初始转动速度
        times: 0, //转动次数
        cynum: 50, // 圈数
        win: 0 //中奖位置 0 默认不中奖
      }
    }
  }
  • 第一步,我来填坑了,先把结构搞出来

    结构分析 根据上述参考图,得到 -9 为中间按钮需要特殊处理(必须是-9吗,不,宝贝,随你开心~)
  <ul>
      <li
        :ref="`item${val.order}`"
        :data-index="val.order"
        :class="val.order >= 1 ? 'rw' : ''"
        v-for="val in resultList"
        :key="val.prize_id"
      >
        <div v-if="val.order !== -9">
          <div class="header"><img :src="val.prize_img" alt="" /></div>
          <div class="name">{{ val.name }}</div>
        </div>
        <div v-else class="start" @click.stop.prevent="startGo"></div>
      </li>
    </ul>
  • 第二步,渲染顺序(产品大佬:这不是我要的顺序啊)

    • 设计数据结构

      结构中定义好 order 顺序,无论远端如何调整,只要遵循规则,前端拿到直接根据order排序即可(所以服务端返回的数据可以是无序的)

       
      [
            {
              name: '10点券',
              prize_img: coupon,
              prize_id: 'c10',
              order: 1 // 没错我就是顺序
            },
            {
              name: '20点券',
              prize_img: coupon,
              prize_id: 'c20',
              order: 2
            },
             ......
            {
              name: '80点券',
              prize_img: coupon,
              prize_id: 'c80',
              order: 8
            }
        ]
      
    • 排序

      既然结构规则定义好了,那么我默认就有个一组排序值,-9为中心位置(// 根据 orderList 的顺序重新排列服务端奖品列表

       orderList: [1, 2, 3, 8, -9, 4, 7, 6, 5]
       // 开始排序
       // 处理 最终的列表渲染顺序 已正常的排序思维顺序
          const keyObj = {}
          const arr = []
          const downArr = Object.assign([], val)
          if (downArr.length) {
            downArr.push({ order: -9 })
            downArr.forEach(element => {
              keyObj[element.order] = element
            })
            // 依据数组的顺序填充
            this.orderList.forEach(ele => {
              arr.push(keyObj[ele])
            })
          }
          this.resultList = arr
      
  • 第三步,开始让我跑起来吧

    上活,setTimeout,执行时间 加的越多越慢反之越快
  _rolling () {
      this.lottery.times++
      this._roll_actived() // 设置状态
      // +10 将速度降下来的圈数周期
      if (
        this.lottery.times > this.lottery.cynum + 10 &&
        this.lotterywin === this.index
      ) {
        clearTimeout(this.lottery.timer)
        setTimeout(() => {
          this.resetData()
          this.$emit('change', 'fin', {})
        }, 1000) // 此时间给予用户感受中奖反馈时间
      } else {
        if (this.lottery.times > this.lottery.cynum) this.lottery.speed += 20 // 惯性 越来越慢
        this.index++
        this.lottery.timer = setTimeout(this._rolling, this.lottery.speed)
      }
    }
  • 第四步,设置状态

    干掉上一个样式,新增当前index,调整classList
    _roll_actived () {
        // running 选中的状态
        let pre = this.index - 1
        if (this.index > this.lottery.count) this.index = 1
        const preDom = this.$refs['item' + pre]
        const downDom = this.$refs['item' + this.index]
        if (pre > 0 && preDom) {
          preDom[0].classList.remove('active')
        }
        if (downDom) {
          downDom[0].classList.add('active')
        }
      },
    
  • 第五步,其他拓展

    • 获取真实奖品
    // await api 获取中奖信息 (因为数据结构的定义,这里拿到中奖位置将变得非常 esay)
        let win = 6 // 模拟中奖位置
     // 拿到中奖位置就可以跑毒了~
    
    • 抽奖的生命周期
    this.$emit('change', 'start', {}) // 抽奖开始
    this.$emit('change', 'fin', {}) // 抽奖完成
    

组件使用

  • 使用
import sudoluWrap from '../../components/sudoku/sudoku.vue'
<sudoluWrap @change="lotteryChange" :awardList="awardList"></sudoluWrap>

抽奖效果

我这个录屏git软件有点问题,抓不到特别快的帧,大家想看效果可以跑一跑源代码,文末有,或者参考的快结束的那一段跑毒效果

另外哪位小可爱有比较好的软件可以推荐一下,评论区等你哈~

GIF 2021-5-12 17-42-43.gif

结语

打完收工,以上提供核心思路和一些简单的配置,更加粒度的操作,交给勤快可爱的大家哈~

另附本文-源码地址,欢迎探讨哈~