持续更新中。。。

1. 新增 prizeNum: 3, // 可视区域每列展示的奖品数,展示为三列,每列三条数据,如下图

2. 新增动画过程中再次点击,直接抽奖结束,滚到对应中奖位置

vue前端-老虎机抽奖功能演示

<template>
  <div class="slot-machine">
    <button @click="start">start</button>
    <div class="slot" v-for="(slot, index) in slots" ref="slots" :key="index">
      <h2>{{ slot.title }}</h2>
      <div class="slot__window">
        <div class="slot__wrap">
          <div class="slot__item" v-for="(opt, idx) in slot.items" :key="`${index}_${idx}`">
            <div class="slot__item_content">{{opt}}</div>
          </div>
          <template v-for="prize in prizeNum">
            <div class="slot__item slot__item--copy" :key="prize">
              <div class="slot__item_content">{{slot.items[prize]}}</div>
            </div>
          </template>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
const next = window.requestAnimationFrame ||
  window.webkitRequestAnimationFrame ||
  window.mozRequestAnimationFrame ||
  window.msRequestAnimationFrame ||
  window.oRequestAnimationFrame || function(cb) { window.setTimeout(cb, 1000/60) }
export default {
  data() {
    return {
      slots: [
        {
          title: "When",
          items: ["today", "next week", "last year", "tomorrow", "yesterday"],
        },
        {
          title: "Where",
          items: [
            "at home",
            "at work",
            "at school",
            "at the gym",
            "at the park",
            "at the beach",
            "at the sidewalk",
            "at the city",
          ],
        },
        { title: "How", items: ["cycling", "walking", "swimming", "flying"] },
      ],
      prizeNum: 3, // 可视区域每列展示的奖品数
      opts: null,
      startedAt: null,
    }
  },
  methods: {
    start: function () {
      if (this.opts) {
        // 增加动画过程中,再次点击开始,立即结束动画,且置为对应中将位置
        this.opts.forEach(opt => {
          opt.isFinished = true
          const pos = -opt.finalPos
          opt.el.style.transform = "translateY(" + pos + "px)"
        })
        return
      }
      this.opts = this.slots.map((data, i) => {
        const slot = this.$refs.slots[i]; // map(function(){})利用map便利slots的每一个选项组,最终得到return的返回值
        const itemHeight = document.getElementsByClassName('slot__item')[0].offsetHeight
        const choice = Math.floor(Math.random() * data.items.length); // 随机生成一个[0,data.items.length]的整数(floor向下取整)
        console.log("choice", i, data.items[choice])
        const opts = {
          el: slot.querySelector(".slot__wrap"), //指向奖项元素的父级
          finalPos: choice * itemHeight, // itemHeight 为每一个奖品滚动标签的高度
          startOffset: 1000 + Math.random() * 500 + i * 500, // 影响转的圈数
          height: data.items.length * itemHeight,
          duration: 3000 + i * 700, // milliseconds
          isFinished: false,
        };
        return opts
      })
      console.log(this.opts) //这个时候this.opts已经和opts一模一样了
      next(this.animate) // 开启动画
    },
    animate: function (timestamp) {
      if(!this.opts) return
      // timestamp当前的方法持续的毫秒数
      if (this.startedAt == null) {
        this.startedAt = timestamp // 动画初始时间
      }
      const timeDiff = timestamp - this.startedAt; //动画持续的时间
      console.log(timestamp, this.opts)
      this.opts.forEach((opt) => {
        if (opt.isFinished) {
          return
        }
        const timeRemaining = Math.max(opt.duration - timeDiff, 0); // 总的持续时间 - 动画持续时间 = 剩下的时间,0表示结束
        const power = 3
        const offset =
          (Math.pow(timeRemaining, power) / Math.pow(opt.duration, power)) *
          opt.startOffset; // Math.pow(timeRemaining, power)表示: timeRemaining 的3 次幂; // negative, such that slots move from top to bottom
        const pos = -1 * Math.floor((offset + opt.finalPos) % opt.height)
        opt.el.style.transform = "translateY(" + pos + "px)"
        if (timeDiff > opt.duration) {
          console.log('finished', opt, pos, opt.finalPost)
          opt.isFinished = true
        }
      })
      if (this.opts.every((o) => o.isFinished)) {
        this.opts = null
        this.startedAt = null
        console.log('finished')
      } else {
        next(this.animate)
      }
    },
  },
};
</script>
<style lang="less" scoped>
.slot {
  float: left;
  margin: 0.4em;
}
.slot__window {
  background-color: green;
  width: 100px;
  height: 80px;
  overflow: hidden;
}
.slot__item {
  padding-top: 20px;
  width: 100px;
  height: 80px;
}
.slot__item_content{
  margin: auto;
  height: 40px;
  width: 80px;
  text-align: center;
  background-color: blue;
  color: white;
  line-height: 40px;
}
</style>

 

 

Logo

前往低代码交流专区

更多推荐