华为抽奖效果的简单实现

1,283 阅读1分钟

项目前提

快过年了嘛,想换个手机,感觉除了水果就是华为了。我锤粉,可惜锤子倒闭了。在华为官网活动页面的最下面有一个转盘抽奖功能,觉得蛮有趣的(该死的前端职业毛病),想想手机没买总要带点什么走,同时很久都没有写一下原生JS了,于是乎就想着把这个东西简单的实现一下(没有考虑封装哈)。本案例不适合大佬。

上图

思路整理

1、DOM结构

    <div id="allParent">
      <!--点击开始/返回-->
      <div class="selectBox">
        <div class="parent">
          <div class="start"></div>
          <div class="back">
            <img
              src="https://res7.vmallres.com/shopdc/pic/9c9af0eb-4c3d-4053-ae33-fd5f3fe90492.png"
              alt=""
            />
          </div>
        </div>
      </div>
    </div>

2、翻转效果3D

首先要给最外层添加透视属性

    #allParent .item .parent {
        width: 100%;
        height: 100%;
        transform-style: preserve-3d; //子节点透视
        perspective-origin: center; 
        perspective: 500px; //透视距离
        position: relative;
      }

奖品和点击翻盘是两个并在一起的图片,默认先把点击翻盘进行旋转。

     #allParent .item .parent .back{
        position: absolute;
        height: 100%;
        transition: all .6s;
        transform: rotateY(270deg) ; //先转270border-radius: 9px;
        opacity: 0;
      }

3、JS效果

核心代码是计算每个奖项相对于中心位置的偏移量。

基本思路:

   function initPosition() { //计算位置
     var gapW = (allParentWidth - boxWidth * 3) / 4, //宽度空格的距离
       gapH = (allParentHeight - boxHeight * 3) / 2; //高度空格的距离
     for (var i = 0; i < itemDoms.length; i++) {
       var pos = {};
       if (i < 3) {
         //第一列
         pos.y = -(gapH + boxHeight); //所有的Y都为盒子的高度+空格的距离
         pos.x = (i - 1) * (boxWidth + gapW);
       } else if (i == 3 || i == 4) {
         //第二列
         if (i == 3) {
           pos.x = -(boxWidth + gapW);
         } else {
           pos.x = boxWidth + gapW;
         }
         pos.y = 0;
       } else {
         //第三列
         pos.y = gapH + boxHeight;
         pos.x = (((i + 1) % 3) - 1) * (boxWidth + gapW);//第三排的x偏移量
       }
       boxsPositions.push(pos);
     }
   }

全部代码

可以直接拷贝运行

<!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>
      * {
        padding: 0;
        margin: 0;
        box-sizing: border-box;
      }

      #allParent {
        width: 716px;
        height: 508px;
        margin: 0 auto;
        position: relative;
        background: radial-gradient(#000000a6, #00000026);
        padding: 10px 0;
        box-sizing: content-box;
      }

      .selectBox {
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
        width: 144px;
        height: 144px;
        z-index: 99
      }

      .selectBox > div > div {
        width: 144px;
        height: 144px;
      }

      .selectBox .start {
        background: url(https://res0.vmallres.com/shopdc/pic/7848e6d2-8420-410e-893d-fbd3b9ac1e78.png)
          no-repeat center center/ cover;
      }
      .selectBox .back {
        display: none;
      }

      .selectBox .back img {
        width: 100%;
        height: 100%;
        border: 0 none;
        vertical-align: top;
      }

      #allParent .item {
        width: 220px;
        height: 160px;
        position: absolute;
        left: 50%;
        top: 50%;
        margin-left: -110px;
        margin-top: -80px;
        z-index: 10;
      }

      #allParent .item .parent {
        width: 100%;
        height: 100%;
        transform-style: preserve-3d;
        perspective-origin: center;
        perspective: 500px;
        position: relative;
      }

      #allParent .item .parent .face {
        transition: all .6s;
        width: 100%;
        height: 100%;
        position: absolute;
        background-color: rgba(248, 113, 13, 0.1);
        transform: rotateY(0deg);
        border: none;
        backface-visibility: hidden;
        
      }
      #allParent .item .parent.active .face{
         transform:rotateY(180deg);
         opacity: 0;
      }

      #allParent .item .parent .back{
        position: absolute;
        height: 100%;
        transition: all .6s;
        transform: rotateY(270deg) ;
        border-radius: 9px;
        opacity: 0;
      }

      #allParent .item .parent.active .back{
        transform: rotateY(360deg) ;
        opacity: 1;
      }

    </style>
  </head>
  <body>
    <div id="allParent">
      <!--点击开始/返回-->
      <div class="selectBox">
        <div class="parent">
          <div class="start"></div>
          <div class="back">
            <img
              src="https://res7.vmallres.com/shopdc/pic/9c9af0eb-4c3d-4053-ae33-fd5f3fe90492.png"
              alt=""
            />
          </div>
        </div>
      </div>
    </div>
  </body>
  <script src="https://res9.vmallres.com/shopdcGray/shopdc/cdn/modules/common/pc/js/jquery-3.5.0.min.js"></script>
  <script>
    var data = [
      {
        img:
          "https://res6.vmallres.com/shopdc/pic/20201231/0924a81c-feff-4686-a4ca-b90913d51d5d.png",
      },
      {
        img:
          "https://res5.vmallres.com/shopdc/pic/a38461b2-8317-4a66-877a-ee3d1ed8ea27.png",
      },
      {
        img:
          "https://res0.vmallres.com/shopdc/pic/20201231/c8214cf6-778a-4dc9-a068-bc91622f3e24.png",
      },
      {
        img:
          "https://res6.vmallres.com/shopdc/pic/20201231/0924a81c-feff-4686-a4ca-b90913d51d5d.png",
      },
      {
        img:
          "https://res5.vmallres.com/shopdc/pic/a38461b2-8317-4a66-877a-ee3d1ed8ea27.png",
      },
      {
        img:
          "https://res0.vmallres.com/shopdc/pic/20201231/c8214cf6-778a-4dc9-a068-bc91622f3e24.png",
      },
      {
        img:
          "https://res2.vmallres.com/shopdcGray/shopdc/pic/f19ce100-4afc-439e-bc90-5b92e4755c07.png",
      },
      {
        img:
          "https://res6.vmallres.com/shopdc/pic/20201231/0924a81c-feff-4686-a4ca-b90913d51d5d.png",
      },
    ];

    var $allParent = $("#allParent"),
      $selectBox = $(".selectBox"),
      $start = $(".start"),
      $back = $(".back")

    var allParentWidth = $allParent.width(),
      allParentHeight = $allParent.height();
    var boxHeight = 160,
      boxWidth = 220;
    var itemDoms = [],
      boxsPositions = [];
    var isFirst = true;

    function init() {
      //初始化事件

      $selectBox.on("click",".start", function () {

         if(isFirst){
            
            itemDoms.forEach(function(dom){
                dom.find(".parent").addClass("active")
            })

            setTimeout(function(){
                for (var i = 0; i < boxsPositions.length; i++) {
                        itemDoms[i].get(0).style.transition = `all 0.6s`
                        itemDoms[i].css({
                        transform: `translate3d(0px, 0px, 0px)`
                        });
                }
                setTimeout(function(){
                    initPricePosition()
                },600)
            },700)
         }else{

            itemDoms.forEach(function(dom){
                dom.find(".parent").addClass("active")
            })

         }

         $start.hide();
         $back.show()

         isFirst = false;
         
      });

      $selectBox.on("click",".back",function(){
            
              
            itemDoms.forEach(function(dom){
                dom.find(".parent").removeClass("active")
            })

            $start.show();
            $back.hide()
      })

    }

    function initDom() { //初始化DOM
      for (var i = 0; i < data.length; i++) {
        var html = $(`<div class="item i${i + 1}">
                            <div class="parent">
                                <div class="face" style='background: url("${
                                  data[i].img
                                }") center center / 100% 100% no-repeat;'>
                                </div>
                                <div class="back">
                                    <img src="https://res0.vmallres.com/shopdc/pic/193f6450-5327-444e-a610-88125afb4ba7.png" style="width: 100%;height: 100%">
                                </div>
                            </div>
                        </div>`);
        itemDoms.push(html);
        $selectBox.before(html);
      }
    }

    function initPosition() { //计算位置
      var gapW = (allParentWidth - boxWidth * 3) / 4, //宽度空格的距离
          gapH = (allParentHeight - boxHeight * 3) / 2; //高度空格的距离
      for (var i = 0; i < itemDoms.length; i++) {
        var pos = {};
        if (i < 3) {
          //第一列
          pos.y = -(gapH + boxHeight);
          pos.x = (i - 1) * (boxWidth + gapW);
        } else if (i == 3 || i == 4) {
          //第二列
          if (i == 3) {
            pos.x = -(boxWidth + gapW);
          } else {
            pos.x = boxWidth + gapW;
          }
          pos.y = 0;
        } else {
          //第三列
          pos.y = gapH + boxHeight;
          pos.x = (((i + 1) % 3) - 1) * (boxWidth + gapW);
        }
        boxsPositions.push(pos);
      }
      //重新给itemDoms赋值 transform
    }

    function initPricePosition() { //初始化DOM位置
      for (var i = 0; i < boxsPositions.length; i++) {
        itemDoms[i].css({
          transform: `translate3d(${boxsPositions[i].x}px, ${boxsPositions[i].y}px, 0px)`,
        });
      }
    }

    init()
    initDom(); //初始化
    initPosition();
    initPricePosition();

  </script>
</html>

总结

小小DEMO,用于练习CSS3+DOM操作,适合刚入行的前端新手。欢迎小伙伴们关注一波,大家一起学习!早日迈向大神之路。