【源码+教程】3D旋转相册(css3+js/纯css)

今天在抖音刷到了一个旋转相册,挺好玩的,就试着写了一下,我只是一个菜鸟,勿喷。另外,演示站请PC端食用,移动端不能拖拽(很卡)


工具:DW/Editplus等等都行、一部电脑/云电脑、有电、一堆图片
由于这是写着玩的,我就没按套路搞了(不喜欢看的,源码在最下面)


OK!步入正题,这里只讲代码,不讲萌新教程(重点都标出来了)
新建站点:名字自取,创建img文件夹存放图片,新建HTML文件

第一步:配置好景深(设置div盒子体现出景深)
首先设置一个盒子,由于是要体现景深的盒子,我就取名为perspective

<div id="perspective"><div>

然后我们需要一个用来放图片的盒子,并插入图片,我就取名为wrap了

<div id="wrap">
    <img src="img/1.jpg" alt="">
    <img src="img/2.jpg" alt="">
    <img src="img/3.jpg" alt="">
    <img src="img/4.jpg" alt="">
    <img src="img/5.jpg" alt="">
    <img src="img/6.jpg" alt="">
    <img src="img/7.jpg" alt="">
    <img src="img/8.jpg" alt="">
    <img src="img/9.jpg" alt="">
    <img src="img/10.jpg" alt="">
    <img src="img/11.jpg" alt="">
 </div>`
第一步布局总代码为:
`<div id="perspective">
 <div id="wrap">
    <img src="img/1.jpg" alt="">
    <img src="img/2.jpg" alt="">
    <img src="img/3.jpg" alt="">
    <img src="img/4.jpg" alt="">
    <img src="img/5.jpg" alt="">
    <img src="img/6.jpg" alt="">
    <img src="img/7.jpg" alt="">
    <img src="img/8.jpg" alt="">
    <img src="img/9.jpg" alt="">
    <img src="img/10.jpg" alt="">
    <img src="img/11.jpg" alt="">
 </div>
 <div>

第二部,页面布局
首先清除默认边距:
*{margin:0;padding:0;}/*清除浏览器默认样式*/
接着把body的滚动条去掉,然后再加一个背景色:

 body{
  background:#66677c;
  overflow:hidden;
  }

做完这些,效果是这样的:
查看原图

然后再把图片缩在一起(wrap里面)相框大小与图片大小等同:

#wrap{
  width:149px;
  height:200px;
  margin:150px auto 0;/*居中*/
 }

到这里效果如下图:
235.png
然后将其叠加:

 #wrap img{
  position:absolute;
}

tips:需要在其父级(wrap)加上相对定位:
position:relative;
效果图如下:
点击查看原图
然后设置景深。之前说了perspective是景深,代码如下:

 #perspective{
  perspective:800px;/*场景景深*/

  }

tips:什么是场景景深?场景景深就类似于一个视角问题。
点击查看原图

然后给wrap元素赋予3D属性:
transform-style:preserve-3d;/*当前元素3D效果*/
设置wrap元素原始度数:
transform:rotateX(-20deg) rotateY(0deg);

然后我们需要计算图片入场动画时所需要旋转的度数,这个我们就交给JavaScript(HTML是从上执行到下的,所以这个放在最后 )
1.求出图片旋转的单位度数 360/图片的个数
①获取到所有图片:
var oImg = document.getElementsByTagName("img");//通过元素的名字获取节
②算出单位度数:
var deg = 360/oImg.length;//单位度数
2.针对每一张图片旋转相对应的度数
call改变数组的forEach方法中的实例执行 用元素集合去代替:

[].forEach.call(oImg,function(node,index){
    console.log(index*deg);//每张图片应该旋转的度数
    node.style.transform = "rotateY("+index*deg+"deg)translatez(350px)";//赋予给图片,并撑开350px
});

①:设置图片精致拖拽,在最前面的<html>里添加ondragstart="return false":
<html ondragstart="return false">

3.入场动画
在第2步的代码里加上过渡属性:
node.style.transition = "1s ";//过渡属性:时间
然后发现这个动画并没有过渡性(延迟加载)于是我搞了一下延迟加载(不加也能用)代码如下:
node.style.transition = "1s "+(oImg.length - index)*0.11+"s";

然后说一下特效是什么?
特效:JS控制元素节点 在指定的时间点改变元素的样式或者属性的值 算法 逻辑思维

4.拖拽元素:分开处理——点击(onmousedown)、移动(onmousemove)、松开(onmouseup)
点击事件:
document.onmousedown = function(e){}
移动事件(位于点击时间内,为什么?你吃饭为什么要煮饭):
document.onmousemove = function(e){}
松开事件(这里还是位于点击事件内,且要结束移动事件):

document.onmouseup =function(e){
     document.onmousemove = null; //清空鼠标移动事件}

接下来就很麻烦了,我也说不清,就不细说了(其实是懒):
5拖拽:

 每一次移动 移动了多少距离  每次鼠标的位置在哪里
 每两次   是   哪两次移动了
 距离   添加到原有的元素度数上
 移动距离差 = 新的移动距离 - 旧的移动距离

①定义六个值:
var newX,newY,pervX,pervY,minusX,minusY;//分别为新值、旧值、差值
②定义的新值使用完后就变成了旧值(移动内):

pervX = newX;
    pervY = newY;//新的值用完之后就变成了旧的值

那么新值是从哪来的呢?
③第一次点击的值(很明显,点击内):

    pervX = e.clientX;
    pervY = e.clientY;//第一次点击时候的值

④保存新值,计算差值,给给出旋转速度(移动内):

  //保存新的鼠标位置的值
    newX = e.clientX;
    newY = e.clientY;


    minusX = newX - pervX;
    minusY = newY - pervY;//差值

    rotateX -= minusY*0.2;
    rotateY += minusX*0.1;//距离差加上当前元素度数

    oWrap.style.transform = "rotateX("+rotateX+"deg) rotateY("+rotateY+"deg)";

重要的差不多就是上面那些了(对了,舞台颜色用文本渲染,这些是没有写惯性的,如果需要自行百度,当然,源码我有,也会放出来),下面放出上面的总代码:
HTML代码

<div id="perspective">
 <div id="wrap">
    <img src="img/1.jpg" alt="">
    <img src="img/2.jpg" alt="">
    <img src="img/3.jpg" alt="">
    <img src="img/4.jpg" alt="">
    <img src="img/5.jpg" alt="">
    <img src="img/6.jpg" alt="">
    <img src="img/7.jpg" alt="">
    <img src="img/8.jpg" alt="">
    <img src="img/9.jpg" alt="">
    <img src="img/10.jpg" alt="">
    <img src="img/11.jpg" alt="">
 </div>
 <div>

css样式

 *{margin:0;padding:0;}
  body{
  background:#66677c;
  overflow:hidden;
  }
  #perspective{
  perspective:800px;/*场景景深*/

  }
  #wrap{
  position:relative;
  width:149px;
  height:200px;
  margin:150px auto 0;
  transform-style:preserve-3d;/*当前元素3D效果*/
  transform:rotateX(-20deg) rotateY(0deg);


  }
  #wrap img{
  position:absolute;
  /*倒影设置*/
  -webkit-box-reflect:below 10px -webkit-linear-gradient(top,rgba(0,0,0,0) 50%,rgba(0,0,0,0.5) 100%);
  cursor:pointer;
    -moz-user-select: -moz-none;
            -moz-user-select: none;
            -o-user-select: none;
            -khtml-user-select: none;
            -webkit-user-select: none;
            -ms-user-select: none;
            user-select: none;
              border-radius:5px;
  box-shadow:0 0 20px #FFF;
  /*背景渐变效果!important*/
  -webkit-box-reflect:below 10px
  -webkit-linear-gradient(top,rgba(0,0,0,0) 80%,rgba(0,0,0,1) 100%);

  }
  #wrap p{
        width: 1200px;
        height: 1200px;
        background: -webkit-radial-gradient(center center,600px 600px,rgba(255,255,255,0.5),rgba(0,0,0,0));
        position: absolute;
        top:100%;left:50%;
        margin-top: -600px;
        margin-left: -600px;
        border-radius:600px;
        transform:rotateX(90deg);
    }

JavaScript代码:

 /*1.求出图片旋转的单位度数 360/图片的个数
   2.针对每一张图片旋转相对应的度数
   3.入场动画
   4.拖拽元素 分开处理事件 点击 移动 松开

   特效:JS控制元素节点 在指定的时间点改变元素的样式或者属性的值 算法 逻辑思维
 */
var oImg = document.getElementsByTagName("img");//通过元素的名字获取节点
var deg = 360/oImg.length;//单位度数
//call改变数组的forEach方法中的实例执行 用元素集合去代替
window.onload = function(){//页面加载完毕之后再执行的脚本
[].forEach.call(oImg,function(node,index){
    console.log(index*deg);
    node.style.transform = "rotateY("+index*deg+"deg)translatez(350px)";
    node.style.transition = "1s "+(oImg.length - index)*0.11+"s";
});
}
/*
拖拽:
     每一次移动 移动了多少距离  每次鼠标的位置在哪里
     每两次   是   哪两次移动了
     距离   添加到原有的元素度数上

     移动距离差 = 新的移动距离 - 旧的移动距离

*/


var newX,newY,pervX,pervY,minusX,minusY;
var rotateX = -20,rotateY = 0;
var oWrap = document.getElementById("wrap");//通过id获取元素
var timer;


//点击
document.onmousedown = function(e){
    pervX = e.clientX;
    pervY = e.clientY;//第一次点击时候的值
    

//移动
  document.onmousemove = function(e){
      //保存新的鼠标位置的值
    newX = e.clientX;
    newY = e.clientY;


    minusX = newX - pervX;
    minusY = newY - pervY;

    rotateX -= minusY*0.2;
    rotateY += minusX*0.1;

    oWrap.style.transform = "rotateX("+rotateX+"deg) rotateY("+rotateY+"deg)";

    pervX = newX;
    pervY = newY;//新的值用完之后就变成了旧的值
  }
  //松开
   document.onmouseup =function(e){
     document.onmousemove = null; //清空鼠标移动事件
     //抬起
                    this.onmouseup = function(){
                        this.onmousemove = null;
                        timer = setInterval(function(){
                            minusX *= 0.95;
                            minusY *= 0.95;
                            rotateY += minusX*0.2; // roY = roY + minusX*0.2;
                            rotateX -= minusY*0.1;
                            oWrap.style.transform = 'rotateX('+ rotateX +'deg) rotateY('+ rotateY +'deg)';

                            if ( Math.abs(minusX)<0.1 && Math.abs( minusY )<0.1 )
                            {
                                clearInterval( timer );
                            }
                            console.log( minusX );
                        },13);
                    }
                    return false;
   }
   
   }

3D旋转相册css+js(拖拽惯性版):点击下载
3D旋转相册(无惯性):点击下载
3D旋转相册(自动旋转):点击下载

tips:音乐可以自己加,记得将demo.html改为index.html;演示站:在线演示

Last modification:July 26th, 2019 at 03:08 pm
If you think my article is useful to you, please feel free to appreciate

11 comments

  1. 康志伟

    求在线演示

  2. 张三无语

    真的很棒!(☆ω☆)

    1. Citrons
      @张三无语

      谢谢,QAQ 鞠躬!

  3. 左利钢

    向大佬学习

    1. Citrons
      @左利钢

      在学习面前,我们都是萌新QAQ

  4. MHun

    那么牛逼的么

    1. Citrons
      @MHun

      嘿嘿嘿

  5. 九日

    原来你研究了一天这个。挺好看

    1. Citrons
      @九日

      可惜没有小姐姐照片,果然,我是找不到女朋友的男人

      1. 九日
        @Citrons

        那就找男朋友吧哈哈哈

        1. Citrons
          @九日

          是个好主意

Leave a Comment