3D翻转盒子图片展示特效(解决鼠标进入不同的边,自动判断进入的是什么方向)

3D翻转盒子图片展示特效

首先展示一下完成的效果,这个demo最难的部分在于鼠标进入不同的边,要自动判断方向,这个问题在后面会有详细的解决办法!
在这里插入图片描述

主要编程思想:样式与行为相分割

第一步:构建html结构

在一个容器中,生成六个小盒子,这里我使用了 ul li 的方式 在每一个li中 有一个 pic-area 用来包裹图片和文字,我这里使用了弹性盒子布局的方式,实现了演示的布局,其他方式也都可以,然后通过把文字区域定位,与图片区重叠,为后续构建立方体做准备,为了看得清楚,我增加了一点点透明度,后期会删掉
在这里插入图片描述

一部分html代码如下:

 <div class="wrapper">
        <ul>
            <li>
                <div class="pic-area">
                    <img src="./tq.jpg" alt="">
                    <p>Lorem, ipsum dolor.</p>
                </div>
            </li>
         <!--  此处是六个li 其他的省略不写了 -->
        </ul>
    </div>

以下是css代码,仅供参考:

*{
    
    
    margin: 0;
    padding: 0;
    list-style: none;
}
.wrapper{
    
    
    width: 1000px;
    height: 650px;
    border: 1px solid #424242;
    margin: 20px auto;
}
ul{
    
    
    width: 100%;
    height: 100%;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
}
ul>li{
    
    
    width: 300px;
    height: 300px;
    margin: 10px;
}
.pic-area{
    
    
    position: relative;
    transform-style: preserve-3d;
    
}
.pic-area img{
    
    
    opacity: 0.4;
}
.pic-area p{
    
    
    position: absolute;
    top: 0;
    left: 0;
    width: 300px;
    height: 300px;
    background-color: #424242;
    font-size: 30px;
    line-height: 300px;
    text-align: center;
    transform: translate3d(0 ,0 ,-1px);
}

第二步:如何实现立方体

首先要注意的是:虽然看起来是一个六面立方体,但是我只用了两个面,我定义了四个方向的类名,鼠标在不同的方向移入,我添加对应的类名即可
我们要翻转的是图片后面的文字部分,注意文字部分在翻转90度的时候,他翻转的中心是在中心的位置,如下图所示,翻转之后还要往上,往里平移
在这里插入图片描述
但是我采用了一种简单的方法,首先平移,然后改变翻转源点,最后直接翻转
在这里插入图片描述
css代码如下:

.in-top .pic-area .hide{
    
    
    transform-origin: bottom;
    transform: translate3d(0,-100%,0) rotate3d(1,0,0,90deg);
}

值得注意的是 不要忘记如下代码,一个是景深属性 ,一个是开启3D模式
在这里插入图片描述

现在应该有一个这样的效果
在这里插入图片描述

同理:四个面四个类名

.in-top .pic-area .hide{
    
    
    transform-origin: bottom;
    transform: translate3d(0,-100%,0) rotate3d(1,0,0,90deg);
}
.in-bottom .pic-area .hide{
    
    
    transform-origin: top;
    transform: translate3d(0,100%,0) rotate3d(-1,0,0,90deg);
}
.in-left .pic-area .hide{
    
    
    transform-origin: right;
    transform: translate3d(-100%,0,0) rotate3d(0,1,0,-90deg);
}
.in-right .pic-area .hide{
    
    
    transform-origin: left;
    transform: translate3d(100%,0,0) rotate3d(0,1,0,90deg);
}

设置在不同的li上看一下现在的效果 如图所示:
在这里插入图片描述
接下来这是转动效果,这里主要通过css3的animate效果来实现
首先改变图片区的转动源,不然会有一个突出去的效果 ,150px是盒子宽高的一半,让盒子的转动轴固定在盒子中心

.pic-area{
    
    
    position: relative;
    transform-style: preserve-3d;
    transform-origin: 50% 50% -150px;
    animation: 0.3s ease-out forwards;
}

紧接着,定义四个关键帧 ,然后给不同的方向添加动画 animation除了name是公有属性,所以提出来在pic-area中一起设置了,下面是分别设置动画名字

.wrapper .in-top .pic-area{
    
    
    animation-name: in-top;
}
.wrapper .in-bottom .pic-area{
    
    
    animation-name: in-bottom;
}
.wrapper .in-left .pic-area{
    
    
    animation-name: in-left;
}
.wrapper .in-right .pic-area{
    
    
    animation-name: in-right;
}
@keyframes in-top{
    
    
    0%{
    
    transform: rotate3d(0,0,0,0)}
    100%{
    
    transform: rotate3d(-1,0,0,90deg)}
}
@keyframes in-bottom{
    
    
    0%{
    
    transform: rotate3d(0,0,0,0)}
    100%{
    
    transform: rotate3d(1,0,0,90deg)}
}
@keyframes in-left{
    
    
    0%{
    
    transform: rotate3d(0,0,0,0)}
    100%{
    
    transform: rotate3d(0,1,0,90deg)}
}
@keyframes in-right{
    
    
    0%{
    
    transform: rotate3d(0,0,0,0)}
    100%{
    
    transform: rotate3d(0,-1,0,90deg)}
}

这是转动之后的效果,这里我也给文字区加了一个透明度
在这里插入图片描述
上面呢是进入的动画,接下来写出去的动画
道理其实很简单,就是把顺序换一下就好了

@keyframes out-top{
    
    
    0%{
    
    transform: rotate3d(-1,0,0,90deg)}
    100%{
    
    transform: rotate3d(0,0,0,0)}
}
@keyframes out-bottom{
    
    
    0%{
    
    transform: rotate3d(1,0,0,90deg)}
    100%{
    
    transform: rotate3d(0,0,0,0)}
}
@keyframes out-left{
    
    
    0%{
    
    transform: rotate3d(0,1,0,90deg)}
    100%{
    
    transform: rotate3d(0,0,0,0)}
}
@keyframes out-right{
    
    
    0%{
    
    transform: rotate3d(0,-1,0,90deg)}
    100%{
    
    transform: rotate3d(0,0,0,0)}
}

添加出去的动画名称

.wrapper .out-top .pic-area{
    
    
    animation-name: out-top;
} 
.wrapper .out-bottom .pic-area{
    
    
    animation-name: out-bottom;
}
.wrapper .out-left .pic-area{
    
    
    animation-name: out-left;
}
.wrapper .out-right .pic-area{
    
    
    animation-name: out-right;
}

添加出去的动画效果,这里我就和进入的动画效果放在了一起写,这样可以减少代码量

.out-top .pic-area .hide,
.in-top .pic-area .hide{
    
    
    transform-origin: bottom;
    transform: translate3d(0,-100%,0) rotate3d(1,0,0,90deg);
}
.out-bottom .pic-area .hide,
.in-bottom .pic-area .hide{
    
    
    transform-origin: top;
    transform: translate3d(0,100%,0) rotate3d(-1,0,0,90deg);
}
.out-left .pic-area .hide,
.in-left .pic-area .hide{
    
    
    transform-origin: right;
    transform: translate3d(-100%,0,0) rotate3d(0,1,0,-90deg);
}
.out-right .pic-area .hide,
.in-right .pic-area .hide{
    
    
    transform-origin: left;
    transform: translate3d(100%,0,0) rotate3d(0,1,0,90deg);
}

四个方向样式的设置原理相同,只要清楚一个方向的样式设置方法就可以。
每一个方向都有一组相应的动画,通过类名来控制,分别是 in-方向out-方向

第三步:也是最重要的一步:如何判断从那个方向进入的呢?

首先:获取li对象,并把li类数组变为数组

    var oLi = Array.prototype.slice.call(document.getElementsByTagName('li'));

给每一个li绑定事件

  oLi.forEach(function(ele ,index){
    
    
        ele.addEventListener('mouseenter',function(e){
    
    
            addClass(this,e);
        })
    })

定义一个增加类名的函数


    function addClass(ele,e) {
    
    
        // 判断从那个方向进入

        // 首先获取鼠标进入的位置 
        var x = e.offsetX - ele.offsetWidth / 2;
        var y = e.offsetY - ele.offsetHeight / 2;

        var deg = Math.atan2(y,x) * (180/Math.PI);  //角度值与弧度值的转换
    }

这是鼠标进入一个盒子的时候会产生一个弧度值,这里我把offsetWidth/2是为了把坐标圆心移动到中间,这样就会得到一周的角度,然后再通过一个数学公式,转化成角度,这就是鼠标进入时的不同角度
在这里插入图片描述
但是这个样子角度的区间会乱,有正有负,所以我给所有的角度都加了180度,这样所以的角度就都变成了一个正数,而且是从0度到360度
在这里插入图片描述
我们不妨来看一下此时各个方向的角度范围

  • top :45~135
  • right:135~225
  • bottom:225~315
  • left:0~45 & 315~360

但是现在这个度数看起来还是不方便我们操作,所以继续化简,给每一个都除以90°
那么现在的角度范围是:

  • top :0.5~1.5
  • right :1.5~2.5
  • bottom :2.5~3.5
  • left :0~0.5 & 3.5~4

继续化简,进行四舍五入取整

  • top :1
  • right:2
  • bottom:3
  • left:0 & 4
    但是现在left中有两个数字代表了一个方向,所以要继续进行处理 ,每一个都+3,之后变为 4,5, 6,3&7 ,然后%4取余4
  • top:0
  • right:1
  • bottom :2
  • left:3
    现在转换为代码:
        var deg = (Math.round((Math.atan2(y,x) * (180/Math.PI)+180) / 90)+3) % 4;

在这里插入图片描述
现在四个方向就可以用一个数字来代表
完整js代码如下:

    var oLi = Array.prototype.slice.call(document.getElementsByTagName('li'));
//获取li对象,并把获取到li类数组转换为数组
    oLi.forEach(function(ele ,index){
    
    
        ele.addEventListener('mouseenter',function(e){
    
    
            addClass(this,e,'in');
        })
        ele.addEventListener('mouseleave',function(e){
    
    
            addClass(this,e,'out');
        })
    })

    function addClass(ele,e,state) {
    
    
        // 判断从那个方向进入

        // 首先获取鼠标进入的位置 
        var x = e.offsetX - ele.offsetWidth / 2;
        var y = e.offsetY - ele.offsetHeight / 2;
        var deg = (Math.round((Math.atan2(y,x) * (180/Math.PI)+180) / 90)+3) % 4;
        
        var direction;
        switch(deg){
    
    
            case 0 :
                direction = 'top';
                break;
            case 1 :
                direction = 'right';
                break;
            case 2 :
                direction = 'bottom';
                break;
            case 3 :
                direction = 'left';
                break; 
        }
        ele.className = state + '-' + direction; // 这里采用了类名拼接的方式
    }

最后这个项目就完成了。

猜你喜欢

转载自blog.csdn.net/qq_43377853/article/details/108267606