html转盘抽奖,conic-gradient+transform

600 阅读2分钟

首先了解下conic-gradient

CSS 函数 conic-gradient() 创建一个由渐变组成的图像,渐变的颜色围绕一个中心点旋转(而不是从中心辐射);用conic-gradient()即可画出转盘扇形布局,如下

<!-- 由此我们可以画出4块扇形 -->
    <div style="margin: 0 auto">
        <div class="conic-gradient"></div>
     </div>
    <style>
        .conic-gradient {
            width: 200px;
            height: 200px;
            border-radius: 9999px;
            background-image: conic-gradient(
              green 0deg,
              green 90deg,
              red 90deg,
              red 180deg,
              pink 180deg,
              pink 270deg,
              blue 270deg,
              blue 360deg
            );
          }
    </style>

如图: shanxing.png

transfrom

如此我们可以借助transfrom:rotate旋转+transition过渡+时间缓动函数写一个转盘旋转效果;

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .conic-gradient {
        width: 200px;
        height: 200px;
        border-radius: 9999px;
        background-image: conic-gradient(
          green 0deg,
          green 90deg,
          red 90deg,
          red 180deg,
          pink 180deg,
          pink 270deg,
          blue 270deg,
          blue 360deg
        );
        transition: transform 3s cubic-bezier(0.25, 0.1, 0.25, 1);
        transform: rotate(0deg);
      }
    </style>
  </head>
  <body>
    <div
      style="
        display: flex;
        justify-content: center;
        flex-direction: column;
        align-items: center;
      "
    >
      <div class="conic-gradient"></div>
      <button style="margin-top: 50px">旋转1800度</button>
    </div>
    <script>
      const btn = document.querySelector("button");
      btn.addEventListener("click", () => {
        const conic = document.querySelector(".conic-gradient");
        conic.style.transform = "rotate(1800deg)";
      });
    </script>
  </body>
</html>

如图所示,现在一个简单的转盘旋转效果就完成啦~ chrome_QrYHkuUXfD.gif

定义抽奖数组,初始化转盘

//抽奖数组
    let prizes = [
          { name: 'iPhone 15 Pro', imageUrl: '📱', uid: '1' },
          { name: 'iPad Air', imageUrl: '📱', uid: '2' },
          { name: 'AirPods Pro', imageUrl: '🎧', uid: '3' },
          { name: 'Apple Watch', imageUrl: '⌚', uid: '4' },
          { name: 'MacBook Pro', imageUrl: '💻', uid: '5' },
          { name: '现金红包', imageUrl: '💰', uid: '6' },
          { name: '优惠券', imageUrl: '🎫', uid: '7' },
          { name: '谢谢惠顾', imageUrl: '😭😭', uid: '0' }
        ]
    //在定义几个需要的变量
    /* 旋转角度 */
    let rotateDeg = 0;
    /* 是否正在旋转 */
    let isSpinning = false;
    /* 是否正在过渡 */
    let transitionActive = true;
    
    //初始化转盘
    function initWheel() {
      const wheel = document.getElementById('wheel');
      const prizeCount = prizes.length;
      const anglePerPrize = 360 / prizeCount;
        
      wheel.innerHTML = '';
      
      //根据奖品数组,生成奖品子元素
      prizes.forEach((prize, idx) => {
            const prizeElement = document.createElement('div');
            prizeElement.className = 'prize';
            prizeElement.style.transform = `rotate(${idx * 360 / prizes.length + 360 / prizes.length / 2}deg) translateY(-180px)`;
            prizeElement.innerHTML = `
                        <div>${prize.name}</div>
                        <div class="prize-icon">${prize.imageUrl}</div>
                    `;
            wheel.appendChild(prizeElement);
          });
          // 更新转盘样式 
          updateWheelStyle();
        }

        // 计算转盘样式
        function getWheelStyle() {
          //计算扇形角度
          const deg = 360 / prizes.length;
          //扇形颜色,这里我复用了3个颜色
          const colors = ['#fff5e1', '#ffbb93', '#ffe4ca'];
          //拼接conic-gradient
          const prizesGradient = prizes.map((item, idx) => {
            return `${colors[idx > 2 ? idx % 3 : idx]} ${idx * deg}deg ${(idx + 1) * deg}deg`;
          }).join(',');

          return {
            transform: `rotate(${rotateDeg}deg)`,
            transition: transitionActive ? 'transform 3s cubic-bezier(0.25, 0.1, 0.25, 1)' : 'none',
            background: `conic-gradient(${prizesGradient})`
          };
        }

        // 更新转盘样式
        function updateWheelStyle() {
          const wheel = document.getElementById('wheel');
          const style = getWheelStyle();
          wheel.style.transform = style.transform;
          wheel.style.transition = style.transition;
          wheel.style.background = style.background;
        }

初始化后样式如图: a.png

抽奖函数

function startLottery() {
      if (isSpinning) return;
      isSpinning = true;

      /* 模拟接口请求 */
      setTimeout(() => {
        /* 中奖下标 */
        const prizeIndex = Math.floor(Math.random() * prizes.length);
        /* 奖品数量 */
        const prizeCount = prizes.length;

        /* 每个奖品的角度 */
        const anglePerPrize = 360 / prizeCount;
        /* 旋转4圈 */
        const baseRotate = 360 * 4;
        /* 目标角度,正好旋转到奖品中间 */
        const targetDeg = baseRotate + (360 - prizeIndex * anglePerPrize) - anglePerPrize / 2
        /* 取消过渡 */
        transitionActive = false;
        /* 旋转角度 */
        rotateDeg = rotateDeg % 360;
        /* 更新样式 */
        updateWheelStyle();
        setTimeout(() => {
          transitionActive = true;
          /* 更新样式-开始过渡 */
          updateWheelStyle();
          setTimeout(() => {
            /* 中奖奖品角度 */
            rotateDeg = targetDeg;
            /* 更新样式-旋转到目标角度 */
            updateWheelStyle();
            setTimeout(() => {
              /* 过渡时间是3秒,所以三秒后再赋值为false,抽奖完成 */
              isSpinning = false;
              console.log(prizes[prizeIndex])
              alert(prizes[prizeIndex].name)
            }, 3000);
          }, 20);
        }, 300);
      }, 500)
    }

开抽~ 谢谢惠顾😭😭😭

chou.gif

完整代码