Ensinar como desenvolver uma animação de loteria Jiugongge

fundo

Há um ditado que diz: "Quando você tem um martelo na mão, vê pregos em todo o mundo". Seguindo o desenvolvimento desenvolveu um componente de lista virtual com uma altura fixa de itens de lista, e o componente de desenvolvimento tornou-se viciado. No projeto recente, uma animação de loteria giratória de nove quadrados deve ser realizada. Parece que esta função pode ser reutilizada. Também se destina a ser feito em um componente. Com o paradigma de desenvolvimento explorado no último componente de desenvolvimento, o componente de desenvolvimento desta vez tem menos problemas do que o componente de desenvolvimento. Agora vamos ao assunto de hoje.

Demonstração de efeito

Primeiro, observe o efeito final. Depois de clicar no botão da loteria, a loteria começa a girar. A animação da loteria muda de lenta para rápida e depois mantém uma velocidade constante. Quando ela para, ela fica mais lenta, o que é mais adequado para o efeito de rotação de objetos do mundo real. A propósito, a função de loteria neste artigo é desenvolvida vue3 + vite + tsadotando o método de desenvolvimento.Se você usar outras pilhas de tecnologia, precisará modificá-la para usá-la.

canal.gif

Ideias de implementação

A animação de sorteio de loteria Jiugongge é o núcleo da função de sorteio de loteria Jiugongge. Conforme mostrado na figura abaixo: Normalmente, a animação do letreiro Jiugongge gira no sentido horário e a sequência de rotação é [1, 2, 3, 6, 9, 8, 7, 4]. Ao virar para qual grade, adicione um estilo de realce a esta grade e parece que tem um efeito cintilante. Além disso, a velocidade de rotação irá variar. No início, ele acelera da velocidade inicial para a velocidade mais rápida, e depois continua girando em velocidade constante. Ao atingir a grade vencedora, a velocidade deve ser reduzida. Como controlar a velocidade de rotação da marquise? Pode ser julgado com base no número de etapas para alcançar a posição atual e no número total de etapas que precisam ser giradas. Por exemplo, no primeiro terço da jornada, deixe o cronômetro acelerar e, no último sexto da jornada, deixe o cronômetro acelerar e mantenha uma velocidade constante no meio da jornada e defina o valor do tempo de o temporizador para um valor fixo.

imagem.png

Faça Você Mesmo

Desenhe uma página estática

Encontrei três fotos na Internet, ou seja, a foto de ouro com desconto instantâneo de 10 yuans, obrigado por participar da foto e a foto do botão de loteria. Use essas três fotos para gerar uma lista de dados de material de 9 grades. Por que usar 9 imagens em vez de uma imagem inteira? A principal razão é que, se você usar uma imagem inteira, o efeito de realce não é fácil de obter ao definir a grade pela qual a marquise passa.


  import { reactive } from 'vue';
  import { NineGridLottery } from '@lib/core';
  import RMBImg from '@/assets/10rmb.png';
  import LotteryBtnImg from '@/assets/lottery-btn.png';
  import ThankImg from '@/assets/thank.png';

  // 奖品列表
  const lotteryList = reactive([
    { name: '10元立减金', pic: RMBImg },
    { name: '谢谢参与', pic: ThankImg },
    { name: '10元立减金', pic: RMBImg },
    { name: '谢谢参与', pic: ThankImg },
    { name: '抽奖', pic: LotteryBtnImg },
    { name: '谢谢参与', pic: ThankImg },
    { name: '10元立减金', pic: RMBImg },
    { name: '谢谢参与', pic: ThankImg },
    { name: '10元立减金', pic: RMBImg },
  ]);

网页结构如下: index=4 时,这个位置是抽奖按钮,抽奖按钮一般交互比较多,所以用插槽的方式暴露给父组件,让父组件去定制。因为slot上不能绑定事件,所以需要在外层加个div,把点击事件绑定在外层的div上。考虑到不同的抽奖活动外观展示都不一样,所以抽奖的样式要允许父组件自定义。这里把抽奖组件的样式类名前缀交给父组件去配置。

<template>
  <div :class="`${props.classPrefix}-box`">
    <div
      v-for="(item, index) in props.lotteryList"
      :class="[`${props.classPrefix}-item`, { active: state.curIndex === index }]"
    >
      <template v-if="index !== 4">
        <img v-if="item.pic" :src="item.pic" class="pic" alt="" />
        <!-- <p class='text'>{{ item.name }}</p> -->
      </template>
      <div v-else @click="start()">
        <slot name="lotteryBtn" :itemData="item"> </slot>
      </div>
    </div>
  </div>
</template>

九宫格抽奖组件的样式是在父组件定义的,九宫格抽奖容器采用flex布局,需要注意的是 flex-wrap默认属性是不换行的,要将属性值设置成wrap。另外下载的png图片不太标准,有色彩的部分并不在png图片背景的正中央,需要向左偏移1px, 看起来左右才对称。转动高亮的效果使用区别于静止状态的背景图和阴影效果实现。

<style lang="less">
  .lottery-box {
    width: 375px;
    height: 375px;
    background: #ea0019;
    margin: 100px auto;
    display: flex;
    flex-wrap: wrap;
    justify-content: space-around;
    align-items: center;
    .lottery-item {
      width: 125px;
      height: 125px;
      position: relative;

      &.active {
        box-shadow: 2px 2px 30px #ffe4c0;
        background-color: #ffe4c0;
      }

      &:nth-of-type(5) {
        cursor: pointer;
      }

      .pic {
        width: 100%;
        height: 100%;
        position: absolute;
        left: -1px;
      }

      .text {
        width: 100%;
        height: 20px;
        background: rgba(0, 0, 0, 0.5);
        color: #fff;
        font-size: 12px;
        text-align: center;
        line-height: 20px;
        position: absolute;
        left: 0;
        bottom: 0;
      }
    }
  }
</style>

让抽奖转盘转起来

首先确定一下九宫格转盘的跑动顺序。顺时针转动时,每个格子的下标为:

 // 跑动顺序
  const lotterySort = [0, 1, 2, 5, 8, 7, 6, 3];

每跑一圈,需要跑八步。到达中奖格子位置跑马灯动画需要跑动的总步数=基本圈数*8+中奖格子在跑动数组中的位置。中奖的id在未跑动前,要先调用后端接口,确定下来。

  // 总执行步数
  const totalSteps = computed(() => {
    return props.baseCircles * 8 + lotterySort.indexOf(props.winId);
  });

跑动时,需要动态设置跑动速率。每次跑动时,清除上一次的速率。每前进一步,重新创建定时器,调整速率。并对到达位置的格子进行高亮显示。当跑动的步数大于等于总步数时,给父组件发消息。

 const timer: Ref<ReturnType<typeof setTimeout> | null> = ref(null);
 const startRun = () => {
    // 延时器的速度要动态调节
    timer.value && clearTimeout(timer.value);

    // console.log(`已走步数=${state.curStep}, 执行总步数=${totalSteps.value}`);

    // 已走步数超过要执行总步数, 则停止
    if (state.curStep >= totalSteps.value) {
      state.isRunning = false;
      return emit('end');
    }

    // 高亮抽奖格子序号
    state.curIndex = lotterySort[state.curStep % 8];
    // 速度调整
    state.speed = calcSpeed(state.speed);

    timer.value = setTimeout(() => {
      state.curStep++;
      startRun();
    }, state.speed);
  };

跑动速率的计算方法,前三分之一的路程,从初始速率加速到最快速率,然后保持最快速率,匀速跑动,到了总路程最后的六分之一时,开始减速,犹如刹车一样,慢慢停下来。

  // 需要加速的前段步数
  const frontSteps = Math.floor(props.baseCircles * 8 * (1 / 3));
  // 需要减速的后段步数
  const midSteps = Math.floor(totalSteps.value * (5 / 6));

  // 计算速度
  const calcSpeed = (speed: number) => {
    // 最快最慢速度
    const { fastSpeed, slowSpeed } = props;
    // 前段加速,中段匀速,后段减速
    if (state.curStep < frontSteps && speed > fastSpeed) {
      speed = speed - Math.floor((props.initSpeed - fastSpeed) / frontSteps);
    } else if (state.curStep > midSteps && speed < slowSpeed) {
      speed = speed + Math.floor((slowSpeed - fastSpeed) / frontSteps / 5);
    }
    return speed;
  };

使用方法

组件有 7 个配置参数:

组件属性名 含义
lotteryList 抽奖列表
winId 中奖 id
classPrefix 九宫格容器和奖项的样式类名前缀
initSpeed 初始转动速度 单位 ms (可选)
baseCircles 基本转动圈数 (可选)
fastSpeed 最快转动速度 单位 ms (可选)
slowSpeed 最慢转动速度 单位 ms (可选)
@end 转动结束事件
<template>
  <NineGridLottery
    :lotteryList="lotteryList"
    :winId="options.winId"
    :initSpeed="options.initSpeed"
    :baseCircles="options.baseCircles"
    @end="handleEnd"
    classPrefix="lottery"
  >
    <template #lotteryBtn="{ itemData }">
      <img :src="itemData.pic" class="pic" alt="" />
    </template>
  </NineGridLottery>
</template>

<script setup lang="ts">
  import { reactive } from 'vue';
  import { NineGridLottery } from '@lib/core';
  import RMBImg from '@/assets/10rmb.png';
  import LotteryBtnImg from '@/assets/lottery-btn.png';
  import ThankImg from '@/assets/thank.png';

  // 奖品列表
  const lotteryList = reactive([
    { name: '10元立减金', pic: RMBImg },
    { name: '谢谢参与', pic: ThankImg },
    { name: '10元立减金', pic: RMBImg },
    { name: '谢谢参与', pic: ThankImg },
    { name: '抽奖', pic: LotteryBtnImg },
    { name: '谢谢参与', pic: ThankImg },
    { name: '10元立减金', pic: RMBImg },
    { name: '谢谢参与', pic: ThankImg },
    { name: '10元立减金', pic: RMBImg },
  ]);

  // 后台配置的奖品数据
  const options = reactive({
    // 中奖id
    winId: 6,
    // 基本圈数 
    baseCircles: 4,
    // 抽奖转动速度
    initSpeed: 300,
    fastSpeed: 100,
    slowSpeed: 600,
  });

  const handleEnd = () => {
    alert('恭喜你中奖了');
  };
</script>

// 样式参照上文
<style lang="less"></style>

结语

Este é o fim da realização dos principais pontos de função da versão vue3+vite4+ts do sorteio rotativo da loteria Jiugongge. Se você deseja obter o código completo do exemplo deste artigo, clique aqui para baixá-lo . Além disso, este componente também foi carregado no site oficial do npm, você pode clicar aqui para visualizar , instalar e usar.

Acho que você gosta

Origin juejin.im/post/7248168880572694588
Recomendado
Clasificación