H5 小游戏开发(红包雨、打地鼠、拼图、老虎机)

一段时间没更新,是因为公司下面的子公司移动端开发需要人员去支援,好了,鄙人被派去了,主要完成四个小游戏的H5开发。接着挨个介绍这四个小游戏我是怎么完成的,以下只贴上核心代码文件,想要直接cv运行的话,可能不行嗷,看懂逻辑,自己去改也是一种学习过程!有问题私信我

红包雨

这里的需求:大小红包,点击大红包10分,小红包5分,点击之后还有打开效果,大红包:小红包比例,二比五。我这里采用的是100以内的随机数,2的整除数和5的整除数。

CountdownTimer.vue 倒计数组件,时间到,跳出游戏结束弹框

<template>
  <div class="countdown_box">
    <p class="countdown">{{ formattedTime }}s</p>
  </div>
</template>

<script>
import { Bus } from '@/util/bus'
export default {
  data() {
    return {
      timeLeft: 15000, // 总时间(毫秒)
      countdownInterval: null,
      microsecondIncrement: 0, // 用于模拟微秒增加
      Count: 0
    }
  },
  computed: {
    formattedTime() {
      const seconds = Math.floor(this.timeLeft / 1000)
      const milliseconds = Math.floor((this.timeLeft % 1000) / 10)
      const microseconds = this.microsecondIncrement % 100
      return `${seconds.toString().padStart(2, '0')}:${milliseconds
        .toString()
        .padStart(2, '0')}:${microseconds.toString().padStart(2, '0')}`
    }
  },
  mounted() {
    this.startCountdown()
    Bus.$on('Total', Total => {
      this.Count = Total
    })
  },
  beforeDestroy() {
    this.stopCountdown()
  },
  methods: {
    startCountdown() {
      this.countdownInterval = setInterval(() => {
        if (this.timeLeft > 0) {
          this.timeLeft -= 10 // 每10毫秒减少10毫秒
          this.microsecondIncrement++ // 模拟微秒增加
          if (this.microsecondIncrement >= 1000) {
            this.microsecondIncrement = 0 // 重置微秒模拟
          }
        } else {
          this.stopCountdown()
          Bus.$emit('countdownEnd', this.Count)
        }
      }, 10) // 每10毫秒更新一次时间
    },
    stopCountdown() {
      clearInterval(this.countdownInterval)
    }
  }
}
</script>
<style lang="less" scoped>
.countdown_box {
  text-align: center;
  color: red;
  .countdown {
    font-size: 9vw;
  }
}
</style>

index.vue 核心代码

<template>
  <div class="rain-wrapper">
    <CountdownTimer style="margin-top: 7.0667vw" ref="cutdown"></CountdownTimer>
    <div ref="rainBox" id="rainBox" class="rainBox">
      <rain-point
        v-for="(item, idx) in rains"
        :key="`rain-point-${idx}`"
        :ref="`rain-point-${idx}`"
        @rainPoinclick="rainPoinclick"
      ></rain-point>
    </div>
  </div>
</template>

<script>
import rainPoint from './tpl.vue'
import countdown from './countdown'
import CountdownTimer from '../CountdownTimer.vue'
import { Bus } from '@/util/bus.js'
export default {
  name: 'rain',
  props: {
    density: {
      // 雨点创建速度
      type: Number,
      default: 600
    },
    delay: {
      // 雨点时长
      type: Number,
      default: 5
    },
    time: {
      // 动画时长(秒)
      type: Number,
      default: 10
    }
  },
  data() {
    return {
      count: 0, // 点击统计
      rains: [], // 组件列表
      rainsCount: 0, // 组件下标
      createTimer: null, // 创建雨点计时器
      flag: true, // 是否结束
      isFiveCount: 0,
      isTenCount: 0,
      event: ''
    }
  },
  components: {
    rainPoint,
    CountdownTimer
  },
  methods: {
    // 结束后回调
    timeoutCallback() {
      this.$emit('timeoutCallback', this.count, this.isFiveCount, this.isTenCount)
    },

    // 点击雨点
    rainPoinclick(e) {
      if (!this.flag) return
      this.count += 1
      if (e.target._prevClass == 'rain-point_small') this.isFiveCount += 1
      if (e.target._prevClass == 'rain-point_big') this.isTenCount += 1
      Bus.$emit('Total', this.Total)
    },
    // 生成随机起始与落点坐标
    grid() {
      let [startX, startY, endX, endY] = [0, 0, 0, 0]
      let rects = document.documentElement.getBoundingClientRect()
      startX = Math.random() * (rects.width - 20)
      startY = -20
      endX = Math.random() * (rects.width - 20)
      endY = rects.height

      return {
        startX,
        startY,
        endX,
        endY
      }
    },

    // 随机速度曲线值
    newCubicBezier() {
      let arr = ['0,.49,1,.3', '.04,.2,.93,.49', '.99,.36,.54,.46'] // 快 中 慢
      // let idx = parseInt(Math.random() * 10) > 2 ? 0 : 1
      let idx = parseInt(Math.random() * 3)
      return arr[idx]
    },

    // 创建雨点
    async create(rainscount) {
      // 生成Dom
      this.rains.push(`rain-point-${rainscount}`)
      // 生成坐标
      let rects = await this.grid()

      // 渲染完成后执行
      await this.$nextTick(async function () {
        // Dom节点
        let el = this.$refs[`rain-point-${rainscount}`][0]

        let initStyleText = {
          transform: `translate(${rects.startX}px, ${rects.startY}px)`
        }
        let actionStyleText = {
          transition: `transform ${this.delay}s cubic-bezier(${this.newCubicBezier()})`,
          transform: `translate(${rects.endX}px, ${rects.endY}px)`
        }
        // 设置初始坐标
        await el.setStyle(initStyleText)
        // 设置结束坐标
        await setTimeout(() => {
          el.setStyle(actionStyleText)
        }, 50)
        // 动画结束
        el.$el.addEventListener('transitionend', el.destory, false)
      })
    },

    // 执行
    start() {
      // this.$nextTick(() => {
      //   this.$refs.cutdown.startCountdown()
      // })
      this.clear()
      // 开启雨点点击
      this.flag = true
      // 重置点击数
      this.count = 0
      // 清除动画定时器
      countdown.clearAssignTimer('rain')
      // 动画定时器
      countdown.creatTimer({
        remainTime: parseInt(this.time) * 1000,
        label: 'rain',
        timeoutFn: () => {
          this.clear()
          this.timeoutCallback()
        }
      })
      // 创建节点
      this.createTimer = setInterval(async () => {
        await this.create(this.rainsCount)
        this.rainsCount += 1
      }, this.density)
    },

    // 停止
    stop() {
      this.flag = false
      clearInterval(this.createTimer)
    },

    // 清空
    clear() {
      this.stop()
      countdown.clearAssignTimer('rain')
      this.rains = []
      this.rainsCount = 0
    }
  },
  computed: {
    Total() {
      return this.isFiveCount * 5 + this.isTenCount * 10
    }
  },
  mounted() {
    // window.start = this.start
    // window.stop = this.stop
    // window.clear = this.clear
    // this.start()
  }
}
</script>

<style>
.rain-wrapper {
  width: 100%;
  height: 250vw;
  /* height: 100%; */
  overflow: hidden;
  position: relative;
}
.rainBox {
  width: 100%;
}
</style>

tpl.vue

<template>
  <div class="tyh">
    <div
      v-if="this.isShow"
      @click="rainPoinclick"
      :class="[
        isClick ? 'action' : '',
        this.isEven ? 'rain-point_small' : this.MultiFive ? 'rain-point_small' : 'rain-point_big'
      ]"
      :style="styleText"
    >
      <transition name="number-fade">
        <div class="addNum" v-if="showNumber">
          <span>+</span>
          <span>{{ this.isEven ? 5 : this.MultiFive ? 5 : 10 }}</span>
        </div>
      </transition>
    </div>
  </div>
</template>

<script>
export default {
  name: 'rain-point',
  props: {},
  data() {
    return {
      styleText: {},
      isShow: true,
      isClick: false,
      // 红包
      total: 0,
      showNumber: false,
      event: ''
    }
  },
  methods: {
    rainPoinclick(e) {
      this.event = e
      if (this.isClick) return
      this.isClick = true
      this.showNumber = true
      // 在动画完成后隐藏数字
      this.$nextTick(() => {
        setTimeout(() => {
          this.showNumber = false
        }, 500) // 动画持续时间,与CSS中的transition-duration保持一致
      })
      this.$emit('rainPoinclick', e)
    },
    setStyle(params) {
      this.styleText = params
    },
    destory() {
      this.isShow = false
    },
    created() {}
  },
  computed: {
    isEven() {
      return Math.floor(Math.random() * 100 + 1) % 2 === 0
    },
    MultiFive() {
      return Math.floor(Math.random() * 100 + 1) % 10 === 0
    }
  },
  watch: {}
}
</script>

<style lang="less" scoped>
.tyh {
  .rain-point_small {
    position: absolute;
    width: 51px;
    height: 65px;
    background-image: url('~@/assets/image/draw/red-envelope-rain/envelope_small.png');
    border-radius: 2.5vw;
  }
  .rain-point_big {
    position: absolute;
    width: 75px;
    height: 95px;
    background-image: url('~@/assets/image/draw/red-envelope-rain/envelope_big.png');
    border-radius: 2.5vw;
  }
  .action {
    width: 90px;
    height: 120px;
    background-image: url('~@/assets/image/draw/red-envelope-rain/envelope_open.png');
  }
  .number-fade-enter-active,
  .number-fade-leave-active {
    transition: opacity 0.5s;
  }
  .number-fade-enter,
  .number-fade-leave-to {
    opacity: 0;
  }
  .addNum {
    font-size: 9vw;
    color: red;
    position: absolute;
  }
}
</style>

打地鼠

倒计时组件和上述红包雨的一样,需要的话自行改造

<template>
  <div class="draw-box">
    <div v-if="centerDialogVisible" class="cover">
      <div class="dialog">
        <div class="el-dialog__header">
          <div class="title">
            {{ isTrue ? '挑战成功!' : '挑战失败!' }}
          </div>
          <img
            :style="isTrue ? 'top:-31vw' : 'top:-22vw'"
            :src="
              isTrue
                ? require('@/assets/image/draw/red-envelope-rain/success.png')
                : require('@/assets/image/draw/red-envelope-rain/fail.png')
            "
          />
        </div>
        <div class="el-dialog__body">
          <div class="content">
            <h1 style="margin-top: 7.7333vw">
              您的成绩为:
              <span style="color: #fa3e56">{{ RankCount }}</span>
            </h1>
            <span
              class="tip"
              v-if="!isTrue"
              :style="isTrue ? 'margin-bottom: 4vw,margin-top:1.333vw' : ''"
            >
              成绩必须达到80分才能抽奖
            </span>
            <div class="divider1"></div>
            <div class="the_Best">
              <div class="BestGrade" style="margin-right: 6vw">
                <span class="text">最佳成绩</span>
                <span class="count">{{ rankBestgrade.bestPoint || RankCount }}</span>
              </div>
              <div class="vertical-divider"></div>
              <div class="BestGrade" style="margin-left: 6vw">
                <span class="text">最佳排名</span>
                <span class="count">NO.{{ rankBestgrade.ranking || 1 }}</span>
              </div>
            </div>
            <div class="divider2"></div>
            <span v-show="isTrue" style="margin-top: 4vw">
              今天还有
              <span style="color: #fa3e56">{{ drawCount }}</span>
              次抽奖机会
            </span>
            <button :style="isTrue ? 'margin-top: 4vw' : 'margin-top: 5vw'" @click="btnClick">
              {{ isTrue ? '去抽奖' : '再玩一次' }}
            </button>
          </div>
        </div>
        <div class="dialog-footer">
          <button class="return" @click="homepage">返回首页</button>
          <button class="charts" @click="toCharts">排行榜</button>
        </div>
      </div>
    </div>

    <div class="content">
      <header>
        <CountdownTimer ref="CutDown"></CountdownTimer>
      </header>
      <div class="row_box">
        <div class="row" v-for="y in size[1]" :key="y">
          <!--在老鼠被击中时 不能触发点击事件-->
          <div
            class="box"
            v-for="x in size[0]"
            :key="x"
            @click.stop.prevent="imgSrc !== imgList[1] && hitGround(x, y)"
          >
            <div class="img_box">
              <img v-show="isShow(x, y)" :src="imgSrc" />
              <!-- <img v-show="true" :src="imgSrc" /> -->
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="footer">
      <img v-if="showImg" class="round" src="@/assets/image/draw/strike-hamster/round.png" alt="" />
      <img
        v-if="showImg"
        class="hammer_dec"
        src="@/assets/image/draw/strike-hamster/hammer_dec.png"
        alt=""
      />
      <img class="bgc1" src="@/assets/image/draw/strike-hamster/game_bg1.png" alt="" />
    </div>

    <fillIn-address
      :visible.sync="fillInVisible"
      :lotteryId="lotteryId"
      :prizeId="activePrizeId"
      :prizeName="activePrizeName"
      :orderId="activeOrderId"
      :loginPhone="loginPhone"
      :isRefresh="true"
    ></fillIn-address>
    <prize-winning
      :visible.sync="winningVisible"
      :activePrizeName="activePrizeName"
      :activePrizeIcon="activePrizeIcon"
      :activePrizeType="activePrizeType"
      :activePrizeTip="activePrizeTip"
      @open-fillIn="openFillIn"
    ></prize-winning>

    <prize-winning-error
      :visible.sync="winningErrorVisible"
      :winningErrorMsg="winningErrorMsg"
    ></prize-winning-error>
  </div>
</template>

<script>
import strikeHamsterIndex from './mixin/index'
import { Bus } from '@/util/bus'
import CountdownTimer from './component/CountdownTimer.vue'
const fillInAddress = () => import('@/components/Address/fillIn.vue')
const prizeWinning = () => import('../component/winning.vue')
const prizeWinningError = () => import('../component/winning-error.vue')
export default {
  name: 'strike-hamster',
  mixins: [strikeHamsterIndex],
  components: {
    CountdownTimer,
    'fillIn-address': fillInAddress,
    'prize-winning': prizeWinning,
    'prize-winning-error': prizeWinningError
  },
  data() {
    return {
      size: [5, 4],
      mouseId: null, // 地鼠随机出现定时器的值
      site: [], // 地鼠出现的位置
      Counts: 0, // 分数
      time: 15, // 游戏倒计时 s
      timerId: null, // 倒计时定时器的值
      // isClick: false, // 是否能点击开始游戏按钮
      level: null, // 难度等级
      speed: 800, // 地鼠出现的速度
      // 地鼠图片
      imgList: [
        require('@/assets/image/draw/strike-hamster/strike_before.png'),
        require('@/assets/image/draw/strike-hamster/strike_after.png')
      ],
      // 当前地鼠的图片
      imgSrc: null,
      showImg: false // 是否显示图片
    }
  },
  mounted() {
    // 适配移动端界面
    this.startGame()
    const ua = navigator.userAgent
    const ipad = ua.match(/(iPad).*OS\s([\d_]+)/)
    const isIphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/)
    const isAndroid = ua.match(/(Android)\s+([\d.]+)/)
    const isMobile = isIphone || isAndroid
    if (isMobile) {
      this.size = [3, 3]
    }
    Bus.$on('countdownEnd', Total => {
      this.countdownEndHandle(Total)
    })
    setTimeout(() => {
      this.showImg = true
    }, 20000)
  },
  methods: {
    toCharts() {
      this.$router.push({
        path: '/StrikeHamster/RankingList',
        query: {
          id: this.lotteryId,
          commonSign: this.commonSign,
          miniprogramParam: this.miniProgramParam
        }
      })
    },
    homepage() {
      this.$router.push({
        path: '/StrikeHamster1',
        query: {
          id: this.lotteryId,
          commonSign: this.commonSign,
          miniprogramParam: this.miniProgramParam
        }
      })
    },

    // 初始化
    ready() {
      // 倒计时结束 不能调用函数
      if (this.time > 0) {
        this.imgSrc = this.imgList[0]
        this.randomSite()
        this.mouseId = setInterval(this.randomSite, this.speed)
      }
    },
    // 渲染地鼠图片
    isShow(x, y) {
      return this.site[0] === x && this.site[1] === y
    },
    // 地鼠位置随机产生
    randomSite() {
      const x = Math.floor(Math.random() * this.size[0] + 1)
      const y = Math.floor(Math.random() * this.size[1] + 1)
      this.site = [x, y]
    },
    // 游戏倒计时
    spendTime() {
      this.timerId = setInterval(() => {
        this.time--
        if (this.time === 0) {
          // 地鼠位置设为空
          this.site = []
          clearInterval(this.mouseId)
          clearInterval(this.timerId)
          // this.isClick = false
          // 弹出游戏结束提示
          // this.$message({
          //   message: '游戏结束',
          //   type: 'success',
          //   center: true,
          //   duration: 1000
          // })
        }
      }, 1000)
    },
    // 打击地鼠
    hitGround(x, y) {
      // 打中地鼠 并且地鼠要出来
      if (this.site[0] === x && this.site[1] === y && this.time > 0) {
        //  增加分数
        this.Counts += 10
        // 切换为打中地鼠的图片
        this.imgSrc = this.imgList[1]
        // 暂停循环
        clearInterval(this.mouseId)
        // 地鼠位置置为空 延迟为了展示被击中的动画
        setTimeout(() => {
          this.site = []
        }, 500)
        //  延迟下 使音效和动作能衔接好 随机时间出现下次地鼠
        setTimeout(() => {
          // 重置地鼠位置和地鼠刷新时间
          this.ready()
        }, 1000)
      }
      Bus.$emit('Counts', this.Counts)
    },
    // 开始游戏
    startGame() {
      // 弹出游戏开始提示
      // this.$message({
      //   message: '游戏开始',
      //   type: 'success',
      //   center: true,
      //   duration: 1000
      // })
      // 初始化时间和分数
      this.time = 20 
      this.Counts = 0 
      this.ready() 
      this.spendTime() 
      // this.isClick = true
    }
  }
}
</script>

<style scope lang="scss">
.draw-box {
  position: relative;
  width: 100vw;
  min-height: 100vh;
  background-color: #f2cb79;
  background-image: url(~@/assets/image/draw/strike-hamster/game_bg.png);
  background-size: 100%;
  background-repeat: no-repeat;
  padding: 3.2vw 0 13.3333vw;
  .cover {
    width: 100vw;
    height: 100vh;
    position: fixed;
    top: 0;
    left: 0;
    z-index: 100;
    background: rgba(0, 0, 0, 0.8);
    .dialog {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      z-index: 100;
      // margin-top: 60.2667vw;
      width: 80vw;
      height: 116vw;
      border-radius: 4vw;
      background-color: #ffefbb;

      .divider1 {
        border-bottom: 1px solid #b3b3b3;
        margin: 4.4vw 0;
        width: 62.4vw;
      }
      .divider2 {
        border-bottom: 1px solid #b3b3b3;
        margin: 4.4vw 0;
        width: 62.4vw;
      }
      .vertical-divider {
        float: left;
        width: 0.1333vw;
        height: 100%;
        background-color: #b3b3b3;
        margin: 0 1vw;
      }
      .el-dialog__header {
        width: 100vw;
        padding: 3.7333vw 15.0667vw 0 38.9333vw;
        .title {
          color: #fa3e56;
          font-size: 6.1333vw;
          font-weight: 700;
        }
        img {
          width: 51.7333vw;
          height: 46.9333vw;
          position: absolute;
          top: -29.2vw;
          left: -10vw;
        }
      }
      .el-dialog__body {
        padding: 9.4667vw 2.6667vw 0;
        .content {
          border-radius: 5vw;
          height: 75vw;
          background-color: #fff;
          display: flex;
          flex-direction: column;
          align-items: center;
          .tip {
            margin-top: 3.3333vw;
            color: #999999;
            font-size: 3.4667vw;
          }
          .the_Best {
            display: flex;
            .BestGrade {
              display: flex;
              flex-direction: column;
              align-items: center;
              .text {
                font-family: AlibabaPuHuiTi-Regular;
                color: #333333;
                font-size: 4vw;
                margin-bottom: 4vw;
              }
              .count {
                color: #e63814;
                font-size: 4vw;
                font-weight: 800;
              }
            }
          }
          button {
            background-color: #e63814;
            font-size: 4.2667vw;
            color: #fff;
            width: 53.3333vw;
            height: 10.6667vw;
            border-radius: 10vw;
            border: 1vw solid #fa3e56;
          }
          .chance_box {
            margin-top: 2vw;
            width: 100%;
            display: flex;
            justify-content: center;
            align-items: center;
            flex-direction: column;
            .morechance {
              font-size: 3.4667vw;
              color: #999999;
            }
            .divider {
              border-bottom: 1px solid #b3b3b3;
              margin-top: 1vw;
            }
          }
        }
      }
      .dialog-footer {
        margin-top: 4.6667vw;
        .return,
        .charts {
          margin-left: 8.8vw;
          width: 28.5333vw;
          height: 10.6667vw;
          border-radius: 5vw;
          font-size: 4.2667vw;
          background-color: #ffefbb;
          color: #e63814;
          border: 0.5vw solid #e63814;
        }
      }
    }
  }

  .footer {
    position: absolute;
    bottom: 0vw;
    width: 100%;
    .bgc1 {
      width: 100%;
    }
    .round {
      transition: transform 0.2s;
      position: absolute;
      left: 40vw;
    }
    .round:hover {
      transform: scale(1.5);
    }
    .hammer_dec:hover {
      transform: scale(1.5);
    }
    .hammer_dec {
      transition: transform 0.2s;
      position: absolute;
      left: 46vw;
    }
  }
  .content {
    height: 100%;
    width: 100%;

    header {
      // padding: 2.6667vw 6.6667vw 1.3333vw;
      width: 100%;
      top: 10vw;
      position: absolute;
      left: 6vw;
      > div div {
        display: flex;
        justify-content: space-between;
        align-items: center;
      }
    }
    .row_box {
      margin-top: 28vw;
      .row {
        display: flex;
        .box {
          top: 30vw;
          display: flex;
          justify-content: center;
          width: 50vw;
          height: 35vw;
          cursor: url('~@/assets/image/draw/strike-hamster/hammer.png'), auto;
          background-position: center;
          background-image: url('~@/assets/image/draw/strike-hamster/field.png');
          background-repeat: no-repeat;
          .img_box {
            width: 25vw;
            height: 20vw;
            text-align: center;
            img {
              // object-fit: cover;
              width: 100%;
              height: 100%;
            }
          }
        }
      }
    }
  }
}
</style>

拼图

倒计时组件和上述红包雨的一样,需要的话自行改造

<template>
  <div class="draw-box">
    <div v-if="centerDialogVisible" class="cover">
      <div class="dialog">
        <div class="el-dialog__header">
          <div class="title">
            {{ isTrue ? '挑战成功!' : '挑战失败!' }}
          </div>
          <img
            @click="Cancel"
            class="cancel"
            src="../../../assets/image/draw/jigsaw-puzzle/cancel.png"
            alt=""
          />
          <img
            class="icon"
            :style="isTrue ? 'top:-31vw' : 'top:-22vw'"
            :src="
              isTrue
                ? require('@/assets/image/draw/red-envelope-rain/success.png')
                : require('@/assets/image/draw/red-envelope-rain/fail.png')
            "
          />
        </div>
        <div class="el-dialog__body">
          <div class="content">
            <h1 style="margin-top: 7.7333vw">
              您的成绩为:
              <span style="color: #5280c1">{{ this.completedTime }}s</span>
            </h1>
            <span
              class="tip"
              v-if="!isTrue"
              :style="isTrue ? 'margin-bottom: 4vw,margin-top:1.333vw' : ''"
            >
              <!-- 成绩必须达到80分才能抽奖 -->
              必须在120s内完成才能抽奖
            </span>
            <div class="divider1"></div>
            <div class="the_Best">
              <div class="BestGrade" style="margin-right: 6vw">
                <span class="text">最佳成绩</span>
                <span class="count">{{ rankBestgrade.bestSecond || 0 }} s</span>
              </div>
              <div class="vertical-divider"></div>
              <div class="BestGrade" style="margin-left: 6vw">
                <span class="text">最佳排名</span>
                <span class="count">NO.{{ rankBestgrade.ranking || 1 }}</span>
              </div>
            </div>
            <div class="divider2"></div>
            <span v-show="isTrue" style="margin-top: 4vw">
              今天还有
              <span style="color: #fa3e56">{{ drawCount }}</span>
              次抽奖机会
            </span>
            <button :style="isTrue ? 'margin-top: 4vw' : 'margin-top: 5vw'" @click="btnClick">
              {{ isTrue ? '去抽奖' : '再玩一次' }}
            </button>
          </div>
        </div>
        <div class="dialog-footer">
          <button class="return" @click="homepage">返回首页</button>
          <button class="charts" @click="toCharts">排行榜</button>
        </div>
      </div>
    </div>
    <img class="time_bg" src="@/assets/image/draw/jigsaw-puzzle/time_bg.png" alt="" />
    <div class="sample"
      ><img src="@/assets/image/draw/jigsaw-puzzle/topleft_corner.png" alt=""
    /></div>

    <div class="content">
      <div class="time_text">用时:</div>
      <header>
        <CountdownTimer></CountdownTimer>
      </header>
      <div class="game_content">
        <div class="puzzle_game">
          <div class="wrap" ref="wrap">
            <div class="play-page">
              <div class="play-area" id="playArea">
                <div
                  v-for="item in boxArr"
                  :index="item"
                  :key="item"
                  :class="['piece', 'piece-' + item, item == boxArractivelass ? 'active' : '']"
                  :style="{ backgroundImage: 'url(' + selectedImg + ')' }"
                  @click="changePositon($event, item)"
                  :ref="'piece' + item"
                ></div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>

    <div class="footer">
      <img src="@/assets/image/draw/jigsaw-puzzle/game_bg_down.png" alt="" />
    </div>

    <fillIn-address
      :visible.sync="fillInVisible"
      :lotteryId="lotteryId"
      :prizeId="activePrizeId"
      :prizeName="activePrizeName"
      :orderId="activeOrderId"
      :loginPhone="loginPhone"
      :isRefresh="true"
    ></fillIn-address>

    <prize-winning
      :visible.sync="winningVisible"
      :activePrizeName="activePrizeName"
      :activePrizeIcon="activePrizeIcon"
      :activePrizeType="activePrizeType"
      :activePrizeTip="activePrizeTip"
      @open-fillIn="openFillIn"
    ></prize-winning>

    <prize-winning-error
      :visible.sync="winningErrorVisible"
      :winningErrorMsg="winningErrorMsg"
    ></prize-winning-error>
  </div>
</template>

<script>
import JigsawPuzzleIndex from './mixin/index'
import CountdownTimer from './component/CountdownTimer.vue'
const fillInAddress = () => import('@/components/Address/fillIn.vue')
const prizeWinning = () => import('../component/winning.vue')
const prizeWinningError = () => import('../component/winning-error.vue')
export default {
  name: 'home',
  mixins: [JigsawPuzzleIndex],
  components: {
    CountdownTimer,
    'fillIn-address': fillInAddress,
    'prize-winning': prizeWinning,
    'prize-winning-error': prizeWinningError
  },
  data() {
    return {
      size: [5, 4],
      mouseId: null, // 地鼠随机出现定时器的值
      site: [], // 地鼠出现的位置
      Counts: 0, // 分数
      time: 15, // 游戏倒计时 s
      timerId: null, // 倒计时定时器的值
      level: null, // 难度等级

      // 拼图
      startDx: 0, // 初始位移,用于返回上一页
      activeClass: -1,
      boxArractivelass: -1,
      prevIndex: null,
      curIndex: 0,
      curposArr: [],
      clickStartBtn: false,
      uploadimg: '',
      selectedImg: '',
      boxArr: new Array(9).fill(1).map((item, index) => {
        return index
      }),
      pieces: document.querySelectorAll('.piece'),
      pool: this.generateMatrix(3, 30.2667, 28),
      // matrixArr: this.upsetArr(this.generateMatrix(3, 28, 20)),
      matrixArr: this.upsetArr(this.generateMatrix(3, 30.2667, 28)),

      // 30.2667
      //  matrixArr:this.shuffle(this.pieces, this.pool),
      imgArr: [{ url: require('@/assets/image/draw/jigsaw-puzzle/topleft_corner1.png') }],

      wall: 0,
      prevEl: null, // 上一个元素,
      dealtime: 600,
      timer: null,
      issuccess: false,
      canvasUrl: '',
      isVisible: false,
      // isflag: false,
      completedTime: 0
    }
  },
  mounted() {
    this.startGame()
  },
  methods: {
    // start
    getItem(index) {
      this.activeClass = index
    },
    onFileChange(e) {
      var files = e.target.files || e.dataTransfer.files
      if (!files.length) return
      this.createImage(files[0])
    },
    createImage(file) {
      //   var image = new Image();
      var reader = new FileReader()
      var vm = this

      reader.onload = e => {
        vm.uploadimg = e.target.result
        this.imgArr.push({
          url: e.target.result
        })
      }
      reader.readAsDataURL(file)
    },
    startGame(picIndex) {
      //   this.dealtime = 180;
      this.timer = setInterval(this.timeStart, 1000)
      // this.startDx = this.startDx - 100
      // this.transformX(this.$refs.wrap, -100 + 'vw')
      this.selectedImg = this.imgArr[0].url

      this.shuffle(document.querySelectorAll('.piece'), this.pool)
    },
    // reOrder() {
    //   this.shuffle(document.querySelectorAll('.piece'), this.pool)
    // },
    // 点击高亮并且切换对应位置 (想办法交换对应索引位置的x,y值即可)
    changePositon(e, item) {
      //点击小图片切换位置方法
      let reg = /active/g
      this.boxArractivelass = item
      let pieces = document.querySelectorAll('.piece')
      if (!this.wall) {
        this.wall = 1
        this.prevEl = e.target
        for (var i = 0, len = pieces.length; i < len; i++) {
          // 使用replace为了避免元素后期加入其他类名
          pieces[i].className = pieces[i].className.replace(' active', '')
        }
        !reg.test(this.className) && (this.className += ' active')
        // this.className= this.className.replace(' active', '');
      } else {
        this.wall = 0
        var prevIndex = +this.prevEl.getAttribute('index'),
          curIndex = +e.target.getAttribute('index')

        // 置换数组
        this.swap(this.pool, prevIndex, curIndex)
        this.prevEl.style.transform =
          'translate(' + this.pool[prevIndex].x + 'vw,' + this.pool[prevIndex].y + 'vw' + ')'
        e.target.style.transform =
          'translate(' + this.pool[curIndex].x + 'vw,' + this.pool[curIndex].y + 'vw' + ')'
        // 清除样式
        // this.prevEl.className= this.prevEl.className.replace(' active', '');
        this.boxArractivelass = -1

        // 校验是否成功
        if (this.isTestSuccess(this.pool)) {
          this.completedTime = 600 - this.dealtime
          if (this.completedTime < 120) {
            this.centerDialogVisible = true
            this.isTrue = true
            this.countdownEndHandle(this.completedTime)
          } else {
            this.centerDialogVisible = true
            this.isTrue = false
          }

          // 清除计时器
          // this.clickStartBtn = true;
          clearInterval(this.timer)
          this.startDx -= 100
          this.issuccess = true

          // alert('成功')

          // $('#playArea')[0].classList.add('active');
          // $('#use_time').html(180-dealtime);
          //   setTimeout(function() {
          // this.transformX(this.$refs.wrap, this.startDx + 'vw')
          //   }, 1200);
        }
      }
    },

    timeStart() {
      this.dealtime--
      if (this.dealtime < 1) {
        this.centerDialogVisible = true
        this.isTrue = false
        this.isflag = false
        clearInterval(this.timer)
        // alert('挑战失败,请返回重新开始')
      }
    },
    // overtime(num) {
    //   this.step = num;
    // },
    // 滑动元素
    transformX(el, dx) {
      el.style.transform = 'translateX(' + dx + ')'
    },
    // onceAgain() {
    //   this.shuffle(document.querySelectorAll('.piece'), this.pool)
    //   this.startDx = -100
    //   this.transformX(this.$refs.wrap, this.startDx + 'vw')
    //   this.resetTime()
    //   this.dealtime = 180
    //   this.timer = setInterval(this.timeStart, 1000)
    //   //    this.$refs.child.initTime();
    // },
    // reStart() {
    //   this.startDx = this.startDx + 300
    //   this.transformX(this.$refs.wrap, this.startDx + 'vw')
    //   this.resetTime()
    //   // this.dealtime = 180;
    //   // this.timer = setInterval(this.timeStart, 1000);
    // },

    // 生成n维矩阵
    generateMatrix(n, dx, dy) {
      var arr = [],
        index = 0
      for (var i = 0; i < n; i++) {
        for (var j = 0; j < n; j++) {
          arr.push({ x: j * dx, y: i * dy, index: index })
          index++
        }
      }
      return arr
    },

    shuffle(els, arr) {
      this.upsetArr(arr)
      for (var i = 0, len = els.length; i < len; i++) {
        var el = els[i]
        el.setAttribute('index', i) // 将打乱后的数组索引缓存到元素中
        el.style.transform = 'translate(' + arr[i].x + 'vw,' + arr[i].y + 'vw' + ')'
      }
    },
    upsetArr(arr) {
      // 方法1:
      return arr.sort(function () {
        return Math.random() > 0.5 ? -1 : 1
      })
    },
    // 置换数组(对应索引的x,y值进行交换)
    swap(arr, indexA, indexB) {
      // let targetArr = [];
      // arr.map(item => {
      //   if (item.index == indexA || item.index == indexB) {
      //     targetArr.push(item);
      //   }
      // });
      // [targetArr[0].x, targetArr[1].x] = [targetArr[1].x, targetArr[0].x];
      // [targetArr[0].y, targetArr[1].y] = [targetArr[1].y, targetArr[0].y];

      // return targetArr;
      // var cache = arr[indexA];
      // arr[indexA] = arr[indexB];
      // arr[indexB] = cache;

      // ES6的解耦交换方式: [arr[index], arr[n]] = [arr[n], arr[index]];
      ;[arr[indexA], arr[indexB]] = [arr[indexB], arr[indexA]]
    },

    // 校验是否成功方法
    isTestSuccess(arr) {
      return arr.every(function (item, i) {
        return item.index === i
      })
    },
    // 将canvas转化为图片
    convertCanvasToImage(canvas, quality) {
      var image = new Image()
      image.src = canvas.toDataURL('image/png', quality)
      return image
    },

    // end
    toCharts() {
      this.$router.push({
        path: '/JigsawPuzzle/RankingList',
        query: {
          id: this.lotteryId
        }
      })
    },
    homepage() {
      this.$router.push({
        path: '/JigsawPuzzle1',
        query: {
          id: this.lotteryId
        }
      })
    },
    Cancel() {
      this.centerDialogVisible = false
      this.$router.push({
        path: '/JigsawPuzzle1',
        query: {
          id: this.lotteryId
        }
      })
    }
  }
}
</script>

<style scope lang="scss">
.draw-box {
  position: relative;
  width: 100vw;
  min-height: 100vh;
  background-color: #178dc5;
  background-image: url(~@/assets/image/draw/jigsaw-puzzle/game_bg_up.png);
  background-size: 100%;
  background-repeat: no-repeat;
  padding: 3.2vw 0 13.3333vw;
  // background-size: cover;
  .footer {
    width: 100%;
    img {
      width: 100%;
    }
    position: absolute;
    bottom: 0vw;
    .round {
      transition: transform 0.2s;
      position: absolute;
      left: 40vw;
    }
    .round:hover {
      transform: scale(1.5);
    }
    .hammer_dec:hover {
      transform: scale(1.5);
    }
    .hammer_dec {
      transition: transform 0.2s;
      position: absolute;
      left: 46vw;
    }
  }
  .time_bg {
    width: 54.4vw;
    height: 15.7333vw;
    position: absolute;
    top: 11.4667vw;
    right: 8vw;
  }
  .sample {
    position: absolute;
    width: 31.0667vw;
    height: 29.0667vw;
    left: 5.6vw;
    top: 3.4667vw;
    img {
      width: 100%;
      height: 100%;
    }
  }
  .content {
    height: 100%;
    width: 100%;
    .time_text {
      font-size: 4vw;
      color: #fff;
      position: absolute;
      top: 16.6667vw;
      right: 37.0667vw;
    }
    header {
      display: flex;
      justify-content: center;
      align-items: center;
      position: absolute;
      top: 15.5333vw;
      right: 13.0667vw;
      > div div {
        display: flex;
        justify-content: space-between;
        align-items: center;
      }
    }
    .game_content {
      width: 100vw;
      height: 118.2667vw;
      position: absolute;
      top: 43.3333vw;
      background-image: url(~@/assets/image/draw/jigsaw-puzzle/game_bg_mid.png);
      background-repeat: no-repeat;
      background-position: center;
      .puzzle_game {
        .wrap {
          // position: absolute;
          display: flex;
          // left: 28.3333vw;
          // transition: transform 1s cubic-bezier(0.52, 0.37, 0.16, 1.32);
        }

        div {
          box-sizing: border-box;
        }

        .btn {
          display: inline-block;
          padding: 10px 60px;
          width: 300px;
          background-color: #06c;
          color: #fff;
          cursor: pointer;
          margin: 40px auto 10px;
          z-index: 10;
        }
        #back {
          margin-top: 10px;
        }
        .play-page,
        .result-page,
        .start-page,
        .start-page .title {
          text-align: center;
        }
        .play-page {
          position: relative;
          width: 100vw;
          // height: 100vh;
        }
        .start-page .title {
          line-height: 4em;
          font-size: 24px;
        }

        .start-page .album-list {
          width: 100%;
          display: flex;
          flex-wrap: wrap;
        }

        .start-page .album-list .img-wrap {
          margin-bottom: 0;
          width: 33.33%;
          height: 22vh;
          overflow: hidden;
        }

        .start-page .album-list .img-wrap.active {
          border: 4px solid #f00;
        }

        .start-page .album-list .img-wrap img {
          width: 100%;
        }

        .start-page .album-list .img-wrap .file-wrap {
          position: relative;
          height: 100%;
          background-position: center center;
          background-size: 100%;
          background-repeat: no-repeat;
        }

        .start-page .album-list .img-wrap .file-wrap::before {
          content: '+';
          position: absolute;
          top: 50%;
          left: 50%;
          transform: translate(-50%, -50%);
          font-size: 60px;
          color: #ccc;
          cursor: pointer;
        }

        .start-page .album-list .img-wrap .file-wrap input {
          position: absolute;
          left: 0;
          top: 0;
          width: 100%;
          height: 100%;
          opacity: 0;
        }

        .start-page-ft {
          position: absolute;
          width: 100%;
          bottom: 20px;
          font-size: 12px;
          text-align: center;
        }

        .start-page-ft a {
          color: #06c;
        }

        .play-page {
          // background-color: #4e2503;
        }
        .play-page .deloy {
          padding: 10px 20px;
          color: #fff;
        }
        .play-page .play-area {
          position: relative;
          // width: 84vw;
          // height: 60vh;
          width: 85.8vw;
          height: 76vw;
          display: flex;
          flex-wrap: wrap;
          margin: 22vw 5.8667vw;
          z-index: 10;
          // margin: 20px auto;
          // background-color: pink;
        }

        .play-page .play-area.active {
          outline-color: #1f8b40;
        }

        .play-page .play-area .piece {
          position: absolute;
          left: 0;
          top: -1.6vw;
          // width: 28vw;
          // height: 20vh;
          width: 30.2667vw;
          height: 28vw;

          border: 1px solid transparent;
          background-repeat: no-repeat;
          // background-size: 84vw 60vh;
          background-size: 90.8vw 84vw;
          transition: transform 0.6s ease-in-out;
        }

        .play-page .play-area .piece.active {
          border: 3px solid red;
        }

        .play-page .play-area .piece-0 {
          background-position: 0 0;
        }

        .play-page .play-area .piece-1 {
          // background-position: -28vw 0;
          background-position: -30.2667vw 0;
        }

        .play-page .play-area .piece-2 {
          background-position: -60.5333vw 0;
        }

        .play-page .play-area .piece-3 {
          // margin-top: -8.8vw;

          background-position: 0 -28vw;
        }

        .play-page .play-area .piece-4 {
          // margin-top: -8.8vw;

          background-position: -30.2667vw -28vw;
        }

        .play-page .play-area .piece-5 {
          // margin-top: -8.8vw;

          background-position: -60.5333vw -28vw;
        }

        .play-page .play-area .piece-6 {
          // margin-top: -17.6vw;

          background-position: 0 -56vw;
        }

        .play-page .play-area .piece-7 {
          // margin-top: -17.6vw;

          background-position: -30.2667vw -56vw;
        }

        .play-page .play-area .piece-8 {
          // margin-top: -17.6vw;

          background-position: -60.5333vw -56vw;
          // background-position: -56vw -40vh;
        }

        .result-page {
          padding-left: 20px;
          padding-right: 20px;
          background-color: #2b2929;
        }

        .result-page .success-text {
          padding-top: 160px;
          padding-bottom: 20px;
          font-size: 36px;
          color: #e4d721;
          font-weight: 700;
        }

        .result-page .total-time {
          display: block;
          margin-bottom: 30px;
          color: #fff;
          font-size: 24px;
        }
        .last-page {
          position: relative;
        }

        .last-page img {
          position: absolute;
          left: 0;
          top: 0;
        }

        .play-again {
          position: absolute;
          bottom: 10px;
          left: 5px;
          z-index: 10;
          width: 48%;
        }

        .share-other {
          position: absolute;
          bottom: 10px;
          right: 5px;
          z-index: 10;
          width: 48%;
        }

        .share-bg {
          position: fixed;
          top: 0;
          width: 0;
          width: 100%;
          height: 100%;
          // background: url('../assets/images/share.png') no-repeat rgba(0, 0, 0, 0.8);
          background-position: top right;
          z-index: 11;
          /* background-size:75%; */
        }
      }
    }
  }
  .cover {
    width: 100vw;
    height: 100vh;
    position: fixed;
    top: 0;
    left: 0;
    z-index: 100;
    background: rgba(0, 0, 0, 0.8);
    .dialog {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      z-index: 100;
      // margin-top: 60.2667vw;
      width: 80vw;
      height: 116vw;
      border-radius: 4vw;
      background-color: #cee7fd;

      .divider1 {
        border-bottom: 1px solid #b3b3b3;
        margin: 4.4vw 0;
        width: 62.4vw;
      }
      .divider2 {
        border-bottom: 1px solid #b3b3b3;
        margin: 4.4vw 0;
        width: 62.4vw;
      }
      .vertical-divider {
        float: left;
        width: 0.1333vw;
        height: 100%;
        background-color: #b3b3b3;
        margin: 0 1vw;
      }
      .el-dialog__header {
        width: 100vw;
        padding: 3.7333vw 15.0667vw 0 38.9333vw;
        .title {
          color: #fa3e56;
          font-size: 6.1333vw;
          font-weight: 700;
        }
        .cancel {
          width: 6.9333vw;
          height: 6.9333vw;
          position: absolute;
          top: -14.6667vw;
          right: -3.4667vw;
        }
        .icon {
          width: 51.7333vw;
          height: 46.9333vw;
          position: absolute;
          top: -29.2vw;
          left: -10vw;
        }
      }
      .el-dialog__body {
        padding: 9.4667vw 2.6667vw 0;
        .content {
          border-radius: 5vw;
          height: 75vw;
          background-color: #fff;
          display: flex;
          flex-direction: column;
          align-items: center;
          .tip {
            margin-top: 3.3333vw;
            color: #999999;
            font-size: 3.4667vw;
          }
          .the_Best {
            display: flex;
            .BestGrade {
              display: flex;
              flex-direction: column;
              align-items: center;
              .text {
                font-family: AlibabaPuHuiTi-Regular;
                color: #333333;
                font-size: 4vw;
                margin-bottom: 4vw;
              }
              .count {
                color: #5280c1;
                font-size: 4vw;
                font-weight: 800;
              }
            }
          }
          button {
            background-color: #5280c1;
            font-size: 4.2667vw;
            color: #fff;
            width: 53.3333vw;
            height: 10.6667vw;
            border-radius: 10vw;
            border: 1vw solid #5280c1;
          }
          .chance_box {
            margin-top: 2vw;
            width: 100%;
            display: flex;
            justify-content: center;
            align-items: center;
            flex-direction: column;
            .morechance {
              font-size: 3.4667vw;
              color: #999999;
            }
            .divider {
              border-bottom: 1px solid #b3b3b3;
              margin-top: 1vw;
            }
          }
        }
      }
      .dialog-footer {
        margin-top: 4.6667vw;
        .return,
        .charts {
          margin-left: 8.8vw;
          width: 28.5333vw;
          height: 10.6667vw;
          border-radius: 5vw;
          font-size: 4.2667vw;
          background-color: #cee7fd;
          color: #5280c1;
          border: 0.5vw solid #5280c1;
        }
      }
    }
  }
}
</style>

老虎机

官网
老虎机这个游戏用的是插件,这个没啥好说的,看官网文档

<template>
  <div class="draw-box">
    <div v-if="phone" class="login">
      {{ phone }}
    </div>

    <div v-if="!miniProgramParam && phone" class="login_out" @click="phoneUnLogin">退出</div>
    <div v-if="!miniProgramParam && !phone" class="login_out" @click="toLogin">登录</div>

    <div class="title">
      <img src="@/assets/image/draw/slot-machine/title.png" alt="" />
    </div>
    <div class="wheel">
      <slot-machine
        ref="SlotMachine"
        class="slot-machine"
        width="66.66vw"
        height="34.66vw"
        :prizes="prizes"
        :defaultConfig="defaultConfig"
        :blocks="blocks"
        :slots="slots"
        @end="endCallBack"
      />
      <img class="wheel-point" src="@/assets/image/draw/slot-machine/machine_bg.png" />
    </div>

    <div class="prize_box" @click="toRecord">
      <span class="myprize_text">我的奖品 ></span>
    </div>
    <div class="count_box">
      <span class="count_text">剩余次数:{{ count }}</span>
    </div>
    <div class="lottery_box">
      <span class="lottery_user">
        <div class="swiper-container">
          <div class="swiper-wrapper">
            <div class="swiper-slide" v-for="(item, index) in winningSwiperList" :key="index">
              <div class="text">{{ item.phone }}获得{{ item.activityPrizesName }}</div>
            </div>
          </div>
        </div>
      </span>
    </div>
    <div class="lottery_btn_box" @click="startCallBack">
      <span class="lottery_btn">抽奖</span>
    </div>
    <div class="left-position-btn">
      <div class="rule-btn" @click="openRule">
        <span>规则</span>
      </div>
      <div class="customer-btn" @click="openCustomer">
        <span>客服</span>
      </div>
    </div>
    <div class="link-btn">
      <div
        v-if="phone && dataForm.isLink === '1' && count === 0"
        class="link-name"
        @click="jumpLink"
      >
        {{ dataForm.linkButtonName }}
      </div>
    </div>

    <fillIn-address
      :visible.sync="fillInVisible"
      :lotteryId="lotteryId"
      :prizeId="activePrizeId"
      :prizeName="activePrizeName"
      :orderId="activeOrderId"
      :loginPhone="loginPhone"
      :isRefresh="true"
    ></fillIn-address>

    <prize-winning
      :visible.sync="winningVisible"
      :activePrizeName="activePrizeName"
      :activePrizeIcon="activePrizeIcon"
      :activePrizeType="activePrizeType"
      :activePrizeTip="activePrizeTip"
      @open-fillIn="openFillIn"
    ></prize-winning>

    <prize-winning-error
      :visible.sync="winningErrorVisible"
      :winningErrorMsg="winningErrorMsg"
    ></prize-winning-error>
    <customer-dialog
      :visible.sync="customerVisible"
      :servicePhone="dataForm.servicePhone"
      :codeUrl="dataForm.qrCodeUrl"
    ></customer-dialog>

    <rule-dialog :visible.sync="ruleVisible" :ruleContent="ruleContent"></rule-dialog>
  </div>
</template>

<script>
import loginHandle from '@/mixin/loginHandle'
import LuckySlotMachineIndex from './mixin/index'
import Swiper from 'swiper'
import { listPrizeSample } from '@/api/draw/index.js'
import { SlotMachine } from '@lucky-canvas/vue'
const fillInAddress = () => import('@/components/Address/fillIn.vue')
const prizeWinning = () => import('./components/winning.vue')
const prizeWinningError = () => import('./components/winning-error.vue')
const customerDialog = () => import('@/components/activityCustomerDialog/index.vue')
const ruleDialog = () => import('@/components/activityRuleDialog/index.vue')
export default {
  mixins: [loginHandle, LuckySlotMachineIndex],
  components: {
    'slot-machine': SlotMachine,
    'fillIn-address': fillInAddress,
    'prize-winning': prizeWinning,
    'prize-winning-error': prizeWinningError,
    'customer-dialog': customerDialog,
    'rule-dialog': ruleDialog
  },
  data() {
    return {
      lotteryId: '', // 抽奖id
      phone: '',
      commonSign: '', // 如果在初始化有值代表测试链接
      time: '',

      blocks: [{ padding: '2.6667vw' }, { padding: '2.6667vw' }],
      slots: [],
      prizes: [],
      defaultStyle: {
        borderRadius: Infinity
      },
      defaultConfig: {
        rowSpacing: '20px',
        colSpacing: '20px'
      },

      winningSwiperList: []
    }
  },
  created() {
    this.listPrizeSample()
  },
  methods: {
    toLogin() {
      this.loginDetermineHandle(this.geLoginQuery())
    },
    geLoginQuery() {
      return {
        path: '/SlotMachine1',
        id: this.lotteryId,
        commonSign: this.commonSign,
        time: this.time
      }
    },

    luckySlotMachineHandle() {
      let prizes = []
      let arr = this.dataForm.prizes
      let length = this.dataForm.prizes.length
      let prizesList = Array.from({ length }, (_, index) => index)
      let order1 = Array.from({ length }, (_, index) => index)
      let order2 = Array.from({ length }, (_, index) => index)
      order1.push(order1.shift())
      order2.unshift(order2.pop())
      if (arr.length <= 1) {
        arr.forEach((item, index) => {
          prizes.push(
            {
              imgs: [
                {
                  src: this.$http + item.uri,
                  width: '95%',
                  height: '100%'
                }
              ]
            },
            {
              imgs: [
                {
                  src: this.$http + item.uri,
                  width: '95%',
                  height: '100%'
                }
              ]
            },
            {
              imgs: [
                {
                  src: this.$http + item.uri,
                  width: '95%',
                  height: '100%'
                }
              ]
            }
          )
        })
      } else if (arr.length === 2) {
        arr.forEach((item, index) => {
          prizes.push(
            {
              imgs: [
                {
                  src: this.$http + item.uri,
                  width: '95%',
                  height: '100%'
                }
              ]
            },
            {
              imgs: [
                {
                  src: this.$http + item.uri,
                  width: '95%',
                  height: '100%'
                }
              ]
            }
          )
        })
      } else {
        arr.forEach((item, index) => {
          prizes.push({
            imgs: [
              {
                src: this.$http + item.uri,
                width: '95%',
                height: '100%'
              }
            ]
          })
        })
      }
      this.slots = [{ order: prizesList }, { order: order1 }, { order: order2 }]
      this.prizes = prizes
    },

    async listPrizeSample() {
      const res = await listPrizeSample({ id: this.lotteryId })
      if (res.data.code == 200) {
        this.winningSwiperList = res.data.data
        this.getSwiper()
      }
    },
    getSwiper() {
      let swiperObj = {
        direction: 'vertical',
        loop: true,
        autoplay: true,
        observer: true,
        observeParents: true,
        pagination: {
          el: '.swiper-pagination'
        }
      }
      let timer = setTimeout(() => {
        clearTimeout(timer)
        new Swiper('.swiper-container', swiperObj)
      }, 500)
    }
  }
}
</script>
<style lang="less" scoped>
.draw-box {
  position: relative;
  width: 100vw;
  min-height: 100vh;
  background-color: #d1f8a0;
  background-image: url(~@/assets/image/draw/slot-machine/bg.png);
  background-size: 100%;
  background-repeat: no-repeat;
  padding: 3.2vw 0 13.3333vw;
  // background-size: cover;
  .swiper-container {
    position: relative;
    z-index: 12;
    width: 100%;
    height: 6vw;
    overflow: hidden;
    .swiper-wrapper {
      height: 100%;
      .swiper-slide {
        width: 61.0667vw !important;
        margin: 0 2.6667vw;
        .text {
          height: 6vw;
          line-height: 6vw;
          padding: 0 1.6vw;
          border-radius: 3.0667vw;
          font-size: 3.2vw;
          text-align: center;
          font-weight: 500;
          color: #ecf1ed;
          overflow: hidden;
          white-space: nowrap;
          text-overflow: ellipsis;
        }
      }
    }
  }
  .link-btn {
    display: flex;
    justify-content: center;
    align-items: center;
    margin-top: 8vw;
    .link-name {
      font-size: 4vw;
      color: #fff;
      border: 1px solid #fff;
      border-radius: 4vw;
      padding: 1vw 2vw;
      cursor: pointer;
    }
  }
  .myprize {
    position: absolute;
    top: 15.5333vw;
    right: 3vw;
    z-index: 10;
    width: 13vw;
    height: 13vw;
    background-color: rgb(255, 255, 255);
    border-radius: 7vw;
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    border: 0.5vw solid #ff071e;
    img {
      width: 10vw;
      height: 10vw;
      margin-top: 2vw;
    }
  }

  .prize_box {
    position: absolute;
    top: 153.5vw;
    z-index: 10;
    left: 39vw;
    .myprize_text {
      z-index: 10;
      font-size: 4vw;
      color: #fff;
      text-shadow: #ff3428 1px 0 0, #ff3428 0 1px 0, #ff3428 -1px 0 0, #ff3428 0 -1px 0;
    }
  }

  .count_box {
    position: absolute;
    top: 120vw;
    z-index: 10;
    left: 37vw;
    .count_text {
      z-index: 10;
      font-size: 4vw;
      color: #fff;
      // text-shadow: #ff3428 1px 0 0, #ff3428 0 1px 0, #ff3428 -1px 0 0, #ff3428 0 -1px 0;
    }
  }
  .lottery_box {
    position: absolute;
    top: 52vw;
    z-index: 10;
    left: 16vw;
    .lottery_user {
      font-size: 4vw;
      color: #fff;
      // text-shadow: #ff3428 1px 0 0, #ff3428 0 1px 0, #ff3428 -1px 0 0, #ff3428 0 -1px 0;
    }
  }
  .lottery_btn_box {
    background-color: #fee532;
    width: 47vw;
    height: 19vw;
    position: absolute;
    top: 129vw;
    z-index: 10;
    left: 24vw;
    border-radius: 4vw;
    text-align: center;
    line-height: 20vw;
    .lottery_btn {
      font-size: 8vw;
      color: red;
      font-weight: bold;
    }
  }
  .login {
    position: absolute;
    top: 2vw;
    left: 3vw;
    color: #fff;
    font-size: 4vw;
    z-index: 10;
  }
  .draw-prize {
    position: relative;
    z-index: 12;
    margin: 3.2vw auto 4.9333vw;
    text-align: center;
    font-size: 4.8vw;
    font-weight: 800;
    color: #6617f8;
  }

  .wheel {
    position: relative;
    margin-top: -6.6667vw;
    z-index: 9;
    width: 100vw;
    height: 181.3333vw;
    .slot-machine {
      position: absolute;
      top: 75.2667vw;
      left: 14.2vw;
      z-index: 10;
    }
    .more-chance {
      position: absolute;
      font-size: 6vw;
      font-weight: 500;
      bottom: -11vw;
      right: 19vw;
      .btn_bg {
        width: 66vw;
        height: 25vw;
      }
      a {
        position: absolute;
        top: 8vw;
        right: 15vw;
        color: #f7462e;
      }
    }
    .wheel-point {
      position: absolute;
      top: 32vw;
      left: -2vw;
      z-index: 9;
      width: 100%;
      height: 80%;
    }
    .wheel-point1 {
      position: absolute;
      right: 9vw;
      bottom: 13vw;
      z-index: 9;
    }
  }
  .title {
    position: absolute;
    top: 10vw;
    right: 10vw;
  }
  .login_out {
    width: 14vw;
    height: 6vw;
    position: absolute;
    top: 2vw;
    right: 3vw;
    color: #36388c;
    font-size: 4vw;
    text-decoration: none;
    border-radius: 2.9333vw;
    background-color: #fff;
    border: #fff;
    text-align: center;
    z-index: 10;
    line-height: 6vw;
  }
  .left-position-btn {
    position: absolute;
    top: 32.5333vw;
    right: 0;
    z-index: 10;
    .prize-btn,
    .customer-btn,
    .rule-btn {
      margin-bottom: 2.5333vw;
      width: 6.0667vw;
      height: 12.8667vw;
      padding: 1.2vw;
      background-color: #fb692f;
      border-radius: 0.9333vw 0 0 0.9333vw;
      font-size: 3.4667vw;
      font-weight: 400;
      color: #fff;
      text-align: center;
      line-height: 4.8667vw;
    }
  }
}
</style>

介绍到这里了,有问题私聊鄙人

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值