前端杂谈 · Web

超炫酷的Web 3d特效

•̀.̫•́✧ · 12月24日 · 2019年 · 本文8057字 · 阅读21分钟354

展示

源码

<!DOCTYPE html>
<html lang='en' onselectstart='return false'>
<head>
<meta charset='utf-8' />
<style>
li,
ul,
div,
html,
body{
  margin: 0;
  padding: 0;
}

html,
body{ height: 100% }

li{ list-style-type: none }

.wrap{
  height: 100%;
  overflow: hidden;
  perspective: 800px;
}

#box{
  top: 50%;
  left: 50%;
  width: 0;
  height: 0;
  position: relative;
  transform-style: preserve-3d;
  transform: translateZ(-1600px);
  z-index: 1;
}
#box li{
  top: -80px;
  left: -60px;
  width: 120px;
  height: 160px;
  position: absolute;
  text-align: center;
  line-height: 160px;
  background-color: rgba(5,100,80,0.2);
  border: 1px solid rgba(125,255,255,0.25);
  box-shadow: 0 0 15px rgba(0,255,255,0.5);
  cursor: pointer;
}
#box li span{
  font-size: 28px;
  font-weight: blod;
  text-shadow: 2px 2px 5px black;
  color: #efebef;
}

.mask{
  width: 100%;
  height: 100%;
  background: url(https://ae01.alicdn.com/kf/H7ce58dae755d438aa718a27094fcb819u.jpg) no-repeat center;
  background-size: cover;
  filter: blur(5px);
}
.mask > .bg-mask{
  width: 100%;
  height: 100%;
  background: #000;
  opacity: 0.25;
}
</style>
</head>
<body>
<div class="wrap">
  <ul id="box"></ul>

  <div class="mask">
    <div class="bg-mask"></div>
  </div>
</div>
<script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script>

// 开启一个独立的空间避免全局变量污染
(function(){
  let

  idx,
  timer,

  // 存放li 元素
  liElem,

  // 存放span 元素
  spanElem,

  // 记录布局类型
  currentStyle,

  // 鼠标X、Y坐标值
  oldCoordX,
  oldCoordY,
  nowCoordX,
  nowCoordY,

  // li 元素水平、垂直、纵深方向偏移位
  offsetStepX,
  offsetStepY,
  offsetStepZ,

  // li 元素的坐标
  liElemCoordX,
  liElemCoordY,
  liElemCoordZ,

  // 鼠标X、Y差值
  minusX = 0,
  minusY = 0,

  // X、Y偏移度数
  liElemDegX = 0,
  liElemDegY = 0,

  // li 元素的最大个数
  liElemMaxNum = 162,

  // li 元素 水平、垂直铺放的最大个数
  liElemRowMaxNum = 5,
  liElemColMaxNum = 5,

  // li 元素水平、垂直、纵深方向的最大间隔距离
  liElemOffsetX = 350,
  liElemOffsetY = 350,
  liElemOffsetZ = 350,

  // li 元素默认景深
  liElemDepDefault = -1000,

  // 避免覆盖默认景深值
  depDefault = liElemDepDefault-600;

  // 避免第一次拖动发生错位
  liElemDepZ = liElemDepDefault-600,

  // 单个方阵中 li 元素的总个数
  aScreenNum = liElemRowMaxNum*liElemColMaxNum,

  // li 元素纵深方向的最在间隔距离
  liElemDepMaxDist = parseInt(liElemMaxNum/aScreenNum),

  // 计算第一个li 元素的坐标点
  liElemFristSiteX = parseInt('-'+liElemRowMaxNum/2)*liElemOffsetX,
  liElemFristSiteY = parseInt('-'+liElemColMaxNum/2)*liElemOffsetY,
  liElemFristSiteZ = parseInt('-'+liElemDepMaxDist/2)*liElemOffsetZ,

  // 文本内容
  data = ['Grid','Helix','Chaotic','Sphere','Three','Geome','Curve','Random'];

  // 指定一个区间,获取一个随机数
  randomFrom = (lowerValue,upperValue) =>{
    return Math.floor(Math.random()*(upperValue-lowerValue+1)+lowerValue);
  }

  // 方阵
  gridLayout = _ =>{
    let arr = [...Array(liElemMaxNum).keys()];
    $('#box li').each(i =>{
      // 数组的索引
      let idx = randomFrom(0,arr.length-1);
      
      // 计算li 元素 水平、垂直、纵深方向的偏移位
      offsetStepX = ((i%aScreenNum)%liElemRowMaxNum)*liElemOffsetX;
      offsetStepY = parseInt((i%aScreenNum)/liElemColMaxNum)*liElemOffsetY;
      offsetStepZ = parseInt(i/aScreenNum)*liElemOffsetZ;

      // 计算当前li 元素的坐标值
      liElemCoordX = liElemFristSiteX+offsetStepX;
      liElemCoordY = liElemFristSiteY+offsetStepY;
      liElemCoordZ = liElemFristSiteZ+offsetStepZ;
       
      $('#box li').eq(arr[idx]).css({
        "transform":`translate3d(${liElemCoordX}px,${liElemCoordY}px,${liElemCoordZ}px)`,
        "transition": "4s ease-in-out"
      })

      // 删除数组中的值
      arr.splice(idx,1);
    }); currentStyle = gridLayout;
  }

  // 螺旋
  helixLayout = _ =>{
    let arr = [...Array(liElemMaxNum).keys()];
    $('#box li').each(i =>{
      let idx = randomFrom(0,arr.length-1);
      let liElemDegY = 10*i;
      let liElemDepY = -10*parseInt(liElemMaxNum/2)+10*i;

      $('#box li').eq(arr[idx]).css({
        "transform":`rotateY(${liElemDegY}deg) translateY(${liElemDepY}px) translateZ(${Math.abs(liElemDepDefault)}px)`,
        "transition": "4s ease-in-out"
      })

      // 删除数组中的值
      arr.splice(idx,1)
    }); currentStyle = helixLayout;
  }

  // 球形
  sphereLayout = _ =>{
    let arr = [...Array(liElemMaxNum).keys()];
    $('#box li').each(i =>{
      let idx = randomFrom(0,arr.length-1);
      let liElemDegY = 3*i;
      let liElemDegX = 30*i;

      $('#box li').eq(arr[idx]).css({
        "transform":`rotateY(${liElemDegY}deg) rotateX(${liElemDegX}deg) translateZ(${Math.abs(liElemDepDefault)}px)`,
        "transition": "4s ease-in-out"
      })

      // 删除数组中的值
      arr.splice(idx,1)
    }); currentStyle = sphereLayout;
  }

  // 三体
  threeLayout = _ =>{
    let arr = [...Array(liElemMaxNum).keys()];
    $('#box li').each(i =>{
      let idx = randomFrom(0,arr.length-1);
      let liElemDegY = 3*i;
      let liElemDegX = 60*i;

      $('#box li').eq(arr[idx]).css({
        "transform":`rotateY(${liElemDegY}deg) rotateX(${liElemDegX}deg) translateZ(${Math.abs(liElemDepDefault)}px)`,
        "transition": "4s ease-in-out"
      })

      // 删除数组中的值
      arr.splice(idx,1)
    }); currentStyle = threeLayout;
  }

  // 几何
  geomeLayout = _ =>{
    let arr = [...Array(liElemMaxNum).keys()];
    $('#box li').each(i =>{
      let idx = randomFrom(0,arr.length-1);
      let liElemDegY = 8.9*i;
      let liElemDegX = 2.9*i;

      $('#box li').eq(arr[idx]).css({
        "transform":`rotateY(${liElemDegY}deg) rotateX(${liElemDegX}deg) translateZ(${Math.abs(liElemDepDefault)}px)`,
        "transition": "4s ease-in-out"
      })

      // 删除数组中的值
      arr.splice(idx,1)
    }); currentStyle = geomeLayout;
  }

  // 曲线
  curveLayout = _ =>{
    let arr = [...Array(liElemMaxNum).keys()];
    $('#box li').each(i =>{
      let idx = randomFrom(0,arr.length-1);
      let liElemDegY = 1*i;
      let liElemDegX = 2*i;

      $('#box li').eq(arr[idx]).css({
        "transform":`rotateY(${liElemDegY}deg) rotateX(${liElemDegX}deg) translateZ(${liElemDepDefault}px)`,
        "transition": "4s ease-in-out"
      })

      // 删除数组中的值
      arr.splice(idx,1)
    }); currentStyle = curveLayout;
  }

  // 随机
  chaoticLayout = _ =>{
    $('#box li').each(function(i){
      // 随机生成li 元素的坐标点
      liElemCoordX = (Math.random()-0.5)*3000;
      liElemCoordY = (Math.random()-0.5)*3000;
      liElemCoordZ = (Math.random()-0.5)*3000;

      $(this).css({
        "transform":`translate3d(${liElemCoordX}px,${liElemCoordY}px,${liElemCoordZ}px)`,
        "transition": "4s ease-in-out"
      })
    }); currentStyle = chaoticLayout;
  }

  function main(){
    $([...Array(liElemMaxNum).keys()]).each(i =>{
      // 创建一个li 元素
      liElem = $('<li></li>');
      let idx = randomFrom(0,data.length-1);

      // 创建一个span 元素
      spanElem = $(`<span>${data[idx]}</span>`);
      liElem.append(spanElem);

      // 设置span 中的文本颜色
      spanElem.css('color',`rgb(${randomFrom(100,255)},${randomFrom(100,255)},${randomFrom(100,255)})`);

      // 将已创建的li 元素添加至容器中
      $('#box').append(liElem);
    })

    // 布局类型
    layoutStyle = [gridLayout, helixLayout, chaoticLayout, sphereLayout, 
    threeLayout, geomeLayout, curveLayout];

    // 鼠标移入移出效果
    $('#box li').hover(function(){
      $(this).css('border','1px solid rgba(125,255,255,0.75)');
      $(this).css('boxShadow','0 0 15px rgba(0,255,255,0.75)');
      $(this).css('transition','0s');
    },function(){
      $(this).css('border','1px solid rgba(125,255,255,0.25)');
      $(this).css('boxShadow','0 0 15px rgba(0,255,255,0.5)');
      $(this).css('transition','0s');
    })

    // 鼠标点击,切换布局
    $('#box li').click(function(){
      switch($(this).text()){
        case 'Grid': gridLayout(); break;
        case 'Helix': helixLayout(); break;
        case 'Three': threeLayout(); break;
        case 'Geome': geomeLayout(); break;
        case 'Curve': curveLayout(); break;
        case 'Sphere': sphereLayout(); break;
        case 'Chaotic': chaoticLayout(); break;

        default:
          while(true){
            idx = randomFrom(0,layoutStyle.length-1);
            if(layoutStyle[idx] != currentStyle){
              return layoutStyle[idx]();
            }
          }
          break;
      }
    })

    // 鼠标拖动与滚轮效果
    $(document).mousedown(function(event){
      event = event || window.event;

      // 上一个点的X、Y坐标
      oldCoordX = event.clientX;
      oldCoordY = event.clientY;

      $(this).on('mousemove',event =>{
        event = event || window.event;

        // 若上一个定时器存在,则将其删除
        timer && clearInterval(timer);

        // 当前点的X、Y坐标
        nowCoordX = event.clientX;
        nowCoordY = event.clientY;

        // 计算机X、Y差值
        minusX = nowCoordX - oldCoordX;
        minusY = nowCoordY - oldCoordY;

        // 更新上一个点的X、Y坐标值
        oldCoordX = nowCoordX;
        oldCoordY = nowCoordY;

        // 计算X、Y轴的移动度数
        liElemDegX -= minusY*0.1;
        liElemDegY += minusX*0.1;

        $('#box').css({
          "transform":`translateZ(${liElemDepZ}px) rotateX(${liElemDegX}deg) rotateY(${liElemDegY}deg)`
        })


      }).mouseup(_ =>{
        // 当鼠标弹起解除移动
        $(document).off('mousemove');

        // 若上一个定时器存在,则将其删除
        timer && clearInterval(timer);
  
        // 鼠标弹起后有缓动效果
        timer = setInterval(_ => {
          // 缓动差值 
          minusX *= 0.95;
          minusY *= 0.95;

          // 计算X、Y轴的移动度数
          liElemDegX -= minusY*0.1;
          liElemDegY += minusX*0.1;

          // 当差值超出指定范围时,则清除定时器
          Math.abs(minusX)<0.05
          && Math.abs(minusY)<0.05
          && clearInterval(timer);

          $('#box').css({
            "transform":`translateZ(${liElemDepZ}px) rotateX(${liElemDegX}deg) rotateY(${liElemDegY}deg)`
          })
        }, 12);
      })

    }).on('mousewheel DOMMouseScroll',e =>{
        // 若上一个定时器存在,则将其删除
        timer && clearInterval(timer);

        // 获取鼠标滚动方向
        let step = (e.originalEvent.wheelDelta
        && (e.originalEvent.wheelDelta >0?1:-1))
        || (e.originalEvent.detail && (e.originalEvent.detail >0?-1:1));

        // 计算滚轮滚动时Z 轴景深的步长
        liElemDepZ = depDefault += step*90;

        $('#box').css({
          "transform":`translateZ(${liElemDepZ}px) rotateX(${liElemDegX}deg) rotateY(${liElemDegY}deg)`
        })

        // 设置缓动效果
        timer = setInterval(_ => {
          // 缓动步长
          step *= 0.6;
          liElemDepZ += step*80;

          Math.abs(step) < 0.000005
          && clearInterval(timer);

          $('#box').css({
            "transform":`translateZ(${liElemDepZ}px) rotateX(${liElemDegX}deg) rotateY(${liElemDegY}deg)`
          })
        }, 12);
      })

    // 加载布局
    setTimeout(gridLayout,1000);
  }

  main();

})();
</script>
</body>
</html>

运行通道

//这里贴要运行的代码
0 条回应