Nine palace pattern of lottery component

Written in front

I changed my career in the middle and bumped into the front end by mistake. It may be due to my 'laziness'. I have never published technical articles or development experience, and I am deeply ashamed. Therefore, I have changed my mind and decided to share something.
This article only describes the tip of the iceberg, welcome to leave a message of valuable experience ~.

1. demand

Page belongs to active page
a. enter the page and request the background interface to pull the remaining times of the current user's Lottery
b. click the start button of the nine palace grid to start turning and request the backstage interface
c. the interface request is successful, and the rotation stops according to the dwell position returned by the interface
The general effect is as follows

2. Component source code

template section

<template>
  <div class="v-common-com-lottery">
    <ul class="list">
      <li class="item" :class="['item' + index, {'active': item.active}]" :key="index" v-for="(item, index) in list">
        <img class="icon" :src="item.img" :alt="item.info" />
        <span class="info">{{item.info}}</span>
        <span class="mask"></span>
      </li>
      <li class="btn" @click="move">
        <span class="text">Button</span>
        <i class="mask"></i>
      </li>
    </ul>
    <div class="lucky-times">
      <span>You have{{luckyTimes}}Chance to draw</span>
    </div>
  </div>
</template>

Part script

<script>
import { post } from '@common/js/ajax';
import { deepQuery } from '@mfw/trans-core';
export default {
  data() {
    return {
      // Award list
      list: [
        { img: 'https://N3-q.mafengwo.net/s12/m00/43/1c/wkged1v_yumqapeuxaabg61crqek46. JPEG ', info:' thank you for your participation ', active: false},
        { img: 'https://B1-q.mafengwo.net/s12/m00/43/1c/wkged1v \,
        { img: 'https://N3-q.mafengwo.net/s12/m00/42/2c/wkged1v \,
        { img: 'https://N3-q.mafengwo.net/s12/m00/43/1c/wkged1v_yumqapeuxaabg61crqek46. JPEG ', info:' ma cellular passport package ', active: false},
        { img: 'https://B1-q.mafengwo.net/s12/m00/43/1c/wkged1v 65123; mqatfwoaa8r6he ﹣ a471. JPEG ', info:' thank you for your participation ', active: false},
        { img: 'https://N3-q.mafengwo.net/s12/m00/42/2c/wkged1v \,
        { img: 'https://B1-q.mafengwo.net/s12/m00/43/1c/wkged1v ﹣ mqatfwoaa8r6he ﹣ a471. JPEG ', info:' mafengwo suitcase ', active: false},
        { img: 'https://N3-q.mafengwo.net/s12/m00/42/2c/wkged1v ﹣ ayagknkaaa33 ﹣ key444. JPEG ', info:' ma cellular calendar ', active: false},
      ],
      // Last stop index
      lastIndex: 0,
      // Server back to stay index
      stopIndex: 0,
      // Normal rotation animation
      timer1: null,
      // Enter slow rotation animation
      timer2: null,
      // Slow rotation animation
      timer3: null,
      // Executing animation
      isMoving: false,
      // Turn for a minimum of 12 times (one and a half turns) to prevent the turning time from being too short
      times: 0,
      // Interface successfully returned stop stopIndex identity
      ajaxEnd: false,
      // Enter slow rotation animation logo
      timerEnd: false,
      // Number of user lottery (actually it should be the number of backstage returns)
      luckyTimes: 5,
    };
  },
  watch: {
    times(val) {
      // If ajax fails during the count
      if (!this.ajaxEnd) {
        return false;
      }
      if (val >= 12) {
        this.timerEnd = true;
      }
    },
  },
  methods: {
    getStopIndex() { // Get the index returned by the server
      post('/lottery')
        .then((res) => {
          if (deepQuery(res, 'data', 'success')) {
            this.stopIndex = deepQuery(res, 'data', 'data');
            if (this.lastIndex !== this.stopIndex || this.lastIndex === this.stopIndex) {
              this.ajaxEnd = true;
            }
          } else {
            return Promise.reject(deepQuery(res, 'data', 'message'));
          }
        })
        .catch((err) => {
          // Initialization data
          clearInterval(this.timer1);
          this.list.map((e) => {
            e.active = false;
          });
          this.lastIndex = 0;
          this.isMoving = false;
          this.lastIndex = 0;
          this.times = 0;
          const errMsg = typeof err === 'string' ? err : 'The server is busy, please try again later';
          this.showToast(errMsg);
        });
    },
    move() { // Click the start game button
      if (!this.luckyTimes) {
        console.error('No more sweepstakes');
        return false;
      }
      if (this.isMoving) {
        return false;
      }
      this.isMoving = true;
      this.ajaxEnd = false;
      this.timerEnd = false;
      this.times = 0;
      console.error('Last stop position: ', this.lastIndex);
      let i = this.lastIndex;
      // Execute ajax request data
      this.getStopIndex();
      // Execution animation
      this.timer1 = setInterval(() => {
        this.times++;
        i++;
        if (i === 8) {
          i = 0;
        }
        this.list.map((e) => {
          e.active = false;
        });
        this.$set(this.list[i], 'active', true);
        // When the server data index is obtained
        if (this.timerEnd) {
          console.log('Stop location returned by server: ', this.stopIndex);
          clearInterval(this.timer1);
          this.enter(i, this.stopIndex);
        }
      }, 100);
    },
    enter(cur, stop) { // Calculate the index to stop
      console.log(cur, stop);
      let count = stop - cur;
      if (count <= 4) {
        count = count > -4 ? count + 8 : count + 16;
      }
      let i = cur;
      this.timer2 = setInterval(() => {
        count--;
        i++;
        if (i === 8) {
          i = 0;
        }
        this.list.map((e) => {
          e.active = false;
        });
        this.$set(this.list[i], 'active', true);
        if (count === 4) {
          clearInterval(this.timer2);
          this.stop(i, stop);
        }
      }, 100);
    },
    stop(cur, stop) { // Calculate the index to stop
      let count = 0;
      let i = cur;
      this.timer3 = setInterval(() => {
        count++;
        i++;
        if (i === 8) {
          i = 0;
        }
        this.list.map((e) => {
          e.active = false;
        });
        this.$set(this.list[i], 'active', true);
        if (count === 4) {
          clearInterval(this.timer3);
          this.isMoving = false;
          this.lastIndex = this.stopIndex;
          this.luckyTimes--;
        }
      }, 300);
    },
    showToast(err) { // toast prompt
      alert(err);
    },
  },
  beforeDestroy() { // Before component destruction
    // Clear timer
    clearInterval(this.timer1);
    clearInterval(this.timer2);
    clearInterval(this.timer3);
  },
};
</script>

Part style

<style lang="scss">
.v-common-com-lottery {
  height: 100%;
  font-size: .24rem;
  color: #fff;
  .list {
    position: relative;
    background: lightblue;
    width: 100%;
    padding-bottom: 100%;
  }
  .item {
    width: 32%;
    padding-bottom: 32%;
    position: absolute;
    background: lightgreen;
    border-radius: .24rem;
    overflow: hidden;
    &.item0 {
      left: 0;
      top: 0;
    }
    &.item1 {
      left: 34%;
      top: 0;
    }
    &.item2 {
      left: 68%;
      top: 0;
    }
    &.item3 {
      left: 68%;
      top: 34%;
    }
    &.item4 {
      left: 68%;
      top: 68%;
    }
    &.item5 {
      left: 34%;
      top: 68%;
    }
    &.item6 {
      left: 0;
      top: 68%;
    }
    &.item7 {
      left: 0;
      top: 34%;
    }
    .icon {
      position: absolute;
      height: 100%;
      width: 100%;
      z-index: 1;
    }
    .info {
      position: absolute;
      left: 0;
      bottom: 0;
      background: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, .5));
      height: .48rem;
      width: 100%;
      z-index: 2;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .mask {
      position: absolute;
      left: 0;
      top: 0;
      z-index: 3;
      width: 100%;
      height: 100%;
      background: rgba(0, 0, 0, .4);
      opacity: 0;
    }
    &.active .mask{
      opacity: 1;
    }
  }

  .btn {
    width: 32%;
    padding-bottom: 32%;
    background: lightsalmon;
    position: absolute;
    left: 34%;
    top: 34%;
    font-size: .72rem;
    border-radius: .24rem;
    overflow: hidden;
    .text {
      position: absolute;
      height: 100%;
      width: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
      z-index: 2;
    }
    .mask {
      position: absolute;
      height: 100%;
      width: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
      z-index: 2;
    }
  }

  .lucky-times {
    color: #000;
    font-size: .36rem;
  }
}
</style>

@common/js/ajax source code is as follows

// https://github.com/axios/axios
const axios = require('axios');


// Timeout 15 seconds
// axios.defaults.timeout = 15000;
// Allow cookie s to be sent
axios.defaults.withCredentials = true;

/**
 * get request
 * @param {string} url - Requested path
 * @param {Object} params - parameter
 * @return {Promise}
 */
export function get(url, params = {}) {
  return axios.get(url, {
    params,
  });
}
/**
 * post request
 * @param {string} url - Requested path
 * @param {Object} data - parameter
 * @param {Object} config - original configuration
 * @return {Promise}
 */
export function post(url, data = {}, config = {}) {
  return axios.post(url, data, config);
}

The source code of deepQuery is as follows

/**
 * Deep query ({}, "a", "B", "C")
 * @param {any} func Objects to query
 * @return {boolean} true or false
 */
export function deepQuery(obj, ...args) {
  return args.reduce((a, b) => (a ? a[b] : a), obj);
}

Tags: Javascript axios github

Posted on Mon, 02 Dec 2019 23:56:38 -0500 by Debar