<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="js/mTween.js"></script>
<style>
body{
background: url(img/bg.jpg);
overflow: hidden;
}
.view{
width: 1000px;
height: 600px;
perspective: 600px;
margin: 100px auto;
}
.bigbox{
width: 100%;
height: 100%;
position: relative;
transform-style: preserve-3d;
}
.box{
width: 200px;
height: 200px;
/* 将元素内-开启3d渲染模式 */
transform-style: preserve-3d;
position:absolute;
}
.box span{
position: absolute;
width: 100%;
height: 100%;
background: #DDD;
opacity: 0;
transition: 1.5s;
}
.show span{
opacity: 1;
}
.box span:nth-child(1){
transform: translateZ(100px);
}
.box span:nth-child(2){
transform:rotateY(90deg) translateZ(100px);
}
.box span:nth-child(3){
transform:rotateY(180deg) translateZ(100px);
}
.box span:nth-child(4){
transform:rotateY(270deg) translateZ(100px);
}
.box span:nth-child(5){
transform:rotateX(90deg) translateZ(100px);
}
.box span:nth-child(6){
transform:rotateX(-90deg) translateZ(100px);
}
.box[data-z="0"] span:nth-child(1){
background-image: url(img/bg1.png);
}
.box[data-z="1"] span:nth-child(1){
background-image: url(img/bg2.png);
}
.box[data-z="2"] span:nth-child(1){
background-image: url(img/1.jpg);
background-size: 1000px 600px;
}
.box[data-z="2"] span:nth-child(2){
background-image: url(img/2.jpg);
background-size: 1000px 600px;
}
.box[data-z="2"] span:nth-child(3){
background-image: url(img/3.jpg);
background-size: 1000px 600px;
}
.box[data-z="2"] span:nth-child(4){
background-image: url(img/4.jpg);
background-size: 1000px 600px;
}
.btnbox{
width: 400px;
margin: 50px auto;
opacity: 0;
transition: 1s;
}
.btnbox button{
width: 100px;
height:100px;
background: url(img/btn.png);
background-size: 100%;
border: none;
outline: none;
cursor: pointer;
}
.btnbox button:nth-child(1){
transform: rotate(180deg);
}
.btnbox button:nth-child(2){
float: right;
}
</style>
</head>
<body>
<div class="view">
<div class="bigbox">
</div>
<div class="btnbox">
<button></button>
<button></button>
</div>
</div>
<script>
//获取bigbox节点
let bigbox=document.querySelector('.bigbox');
//3层 3行 5列 的立方体矩阵 = 45个 // boxw 盒子宽度 boxh盒子高度
let zSize=3,rows=3,ceils=5,boxw=200,boxh=200;
//创建文档碎片
let fragment=document.createDocumentFragment();
for(let z=0;z<zSize;z++){
for(let y=0; y<rows;y++){
for(let x=0;x<ceils;x++){
//创建 立方体
let box=document.createElement('div');
//后期需要用到立方体自己的位置
box.dataset.x=x; //列数
box.dataset.y=y; //行数
box.dataset.z=z; //层数
//添加class
box.classList.add('box');
//添加html文档
box.innerHTML=`
<span style="background-position:-${boxw*x}px -${boxh*y}px">
</span>
<span style="background-position:-${boxw*x}px -${boxh*y}px">
</span>
<span style="background-position:-${boxw*x}px -${boxh*y}px">
</span>
<span style="background-position:-${boxw*x}px -${boxh*y}px">
</span>
<span></span>
<span></span>
`;
box.style.cssText=`
top:${boxh*y}px;
left:${boxw*x}px;
`
// 在 mTween.js 中 有css方法
// 1. 设置样式 css(el,'rotateY',90);
// 2. 获取样式 css(el,'rotateY')
css(box,'translateX',(x-Math.floor(ceils/2))*200*(z+1));
css(box,'translateY',(y-Math.floor(rows/2))*200*(z+1));
css(box,'translateZ',(z+1)*200);
//设置初始值
css(box,'rotateY',0);
//存入到文档碎片中
fragment.appendChild(box);
}
}
}
//插入到dom节点中
bigbox.appendChild(fragment);
//入场动画
let boxs=document.querySelectorAll('.box');
let times=3000;
boxs.forEach(item=>{
let z=item.dataset.z;
let dely=Math.random()*500+z*700;
setTimeout(()=>{
//通过控制class 来使元素有透明度的过渡效果
item.classList.add('show');
// el 设置运动元素
//attrs 设置运动样式
//duration 设置运动时间
mTween({
//运动元素
el:item,
//运动样式
attrs:{
translateX:0,
translateY:0,
translateZ:-100,
},
duration:times-dely
});
},dely);
});
//入场动画完毕时的操作
setTimeout(()=>{
//把前2层盒子 删掉
boxs.forEach(item=>{
if(item.dataset.z<2){
item.remove();
}
})
let btnbox=document.querySelector('.btnbox');
btnbox.style.opacity=1;
},times);
//获取事件元素
let btns=document.querySelectorAll('.btnbox button');
//设置开关
let isPlay=false;
//存储运动形式
let fnArr=[];
let now=0;
btns[0].onclick=function(){
//如果isPlay 是 true 阻止点击事件执行
if(isPlay)return;
isPlay=true;
fnArr[now%fnArr.length](90);
now++
};
btns[1].onclick=function(){
//如果isPlay 是 true 阻止点击事件执行
if(isPlay)return;
isPlay=true;
fnArr[now%fnArr.length](-90);
now++;
};
fnArr[0]=function(deg){
let boxs=document.querySelectorAll('.box');
let times=1000;
boxs.forEach(item=>{
let dely=Math.random()*400;
setTimeout(()=>{
//运动框架
mTween({
el:item,
attrs:{
rotateY:css(item,'rotateY')+deg
},
duration:times-dely
});
},dely);
});
//将开关设置为false
setTimeout(()=>{
isPlay=false;
},times);
}
//分三个运动阶段
//1. 向前平移
//2. 旋转
//3. 向后平移
fnArr[1]=function(deg){
let boxs=document.querySelectorAll('.box');
let tiems=2300;
boxs.forEach(item=>{
let x=item.dataset.x;
let y=item.dataset.y;
let dely= x*80+y*80;
setTimeout(() => {
mTween({
el:item,
attrs:{
translateZ:css(item,'translateZ')+100
},
duration:600,
//当前运动完毕时执行
cb:()=>{
mTween({
el:item,
attrs:{
rotateY:css(item,'rotateY')+deg
},
duration:600,
//当前运动完毕时执行
cb:()=>{
mTween({
el:item,
attrs:{
translateZ:css(item,'translateZ')-100
},
duration:600,
});
}
});
}
});
}, dely);
});
//将开关设置为false
setTimeout(()=>{
isPlay=false;
},times);
}
fnArr[2]=function(deg){
let boxs=document.querySelectorAll('.box');
let times=2200;
boxs.forEach(item=>{
let x=parseInt(item.dataset.x);
let y=parseInt(item.dataset.y);
console.log(x,y);
let dely=Math.random()*400;
//判断方向
let dir=1; // 1 -1
if(x%2){
dir=y%2?-1:1;
}else{
dir=y%2?1:-1;
}
setTimeout(() => {
mTween({
el:item,
attrs:{
translateZ:css(item,'translateZ')+50*dir
},
duration:600,
//当前运动完毕时执行
cb:()=>{
mTween({
el:item,
attrs:{
rotateY:css(item,'rotateY')+deg
},
duration:600,
//当前运动完毕时执行
cb:()=>{
mTween({
el:item,
attrs:{
translateZ:css(item,'translateZ')-50*dir
},
duration:600,
});
}
});
}
});
}, dely);
});
//将开关设置为false
setTimeout(()=>{
isPlay=false;
},times);
}
</script>
</body>
</html>
mTween.js
var normalAttr = [
'width',
'height',
'left',
'top',
'bottom',
'right',
'marginLeft',
'marginTop',
'marginBottom',
'marginRight'
];
var css3Attr = [
'rotate',
'rotateX',
'rotateY',
'skewX',
'skewY',
'translateX',
'translateY',
'translateZ',
'scale',
'scaleX',
'scaleY'
];
var Tween = {
linear: function (t, b, c, d){ //匀速
return c*t/d + b;
},
easeIn: function(t, b, c, d){ //加速曲线
return c*(t/=d)*t + b;
},
easeOut: function(t, b, c, d){ //减速曲线
return -c *(t/=d)*(t-2) + b;
},
easeBoth: function(t, b, c, d){ //加速减速曲线
if ((t/=d/2) < 1) {
return c/2*t*t + b;
}
return -c/2 * ((--t)*(t-2) - 1) + b;
},
easeInStrong: function(t, b, c, d){ //加加速曲线
return c*(t/=d)*t*t*t + b;
},
easeOutStrong: function(t, b, c, d){ //减减速曲线
return -c * ((t=t/d-1)*t*t*t - 1) + b;
},
easeBothStrong: function(t, b, c, d){ //加加速减减速曲线
if ((t/=d/2) < 1) {
return c/2*t*t*t*t + b;
}
return -c/2 * ((t-=2)*t*t*t - 2) + b;
},
elasticIn: function(t, b, c, d, a, p){ //正弦衰减曲线(弹动渐入)
if (t === 0) {
return b;
}
if ( (t /= d) == 1 ) {
return b+c;
}
if (!p) {
p=d*0.3;
}
if (!a || a < Math.abs(c)) {
a = c;
var s = p/4;
} else {
var s = p/(2*Math.PI) * Math.asin (c/a);
}
return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
},
elasticOut: function(t, b, c, d, a, p){ //*正弦增强曲线(弹动渐出)
if (t === 0) {
return b;
}
if ( (t /= d) == 1 ) {
return b+c;
}
if (!p) {
p=d*0.3;
}
if (!a || a < Math.abs(c)) {
a = c;
var s = p / 4;
} else {
var s = p/(2*Math.PI) * Math.asin (c/a);
}
return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
},
elasticBoth: function(t, b, c, d, a, p){
if (t === 0) {
return b;
}
if ( (t /= d/2) == 2 ) {
return b+c;
}
if (!p) {
p = d*(0.3*1.5);
}
if ( !a || a < Math.abs(c) ) {
a = c;
var s = p/4;
}
else {
var s = p/(2*Math.PI) * Math.asin (c/a);
}
if (t < 1) {
return - 0.5*(a*Math.pow(2,10*(t-=1)) *
Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
}
return a*Math.pow(2,-10*(t-=1)) *
Math.sin( (t*d-s)*(2*Math.PI)/p )*0.5 + c + b;
},
backIn: function(t, b, c, d, s){ //回退加速(回退渐入)
if (typeof s == 'undefined') {
s = 1.70158;
}
return c*(t/=d)*t*((s+1)*t - s) + b;
},
backOut: function(t, b, c, d, s){
if (typeof s == 'undefined') {
s = 1.70158; //回缩的距离
}
return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
},
backBoth: function(t, b, c, d, s){
if (typeof s == 'undefined') {
s = 1.70158;
}
if ((t /= d/2 ) < 1) {
return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
}
return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
},
bounceIn: function(t, b, c, d){ //弹球减振(弹球渐出)
return c - Tween['bounceOut'](d-t, 0, c, d) + b;
},
bounceOut: function(t, b, c, d){//*
if ((t/=d) < (1/2.75)) {
return c*(7.5625*t*t) + b;
} else if (t < (2/2.75)) {
return c*(7.5625*(t-=(1.5/2.75))*t + 0.75) + b;
} else if (t < (2.5/2.75)) {
return c*(7.5625*(t-=(2.25/2.75))*t + 0.9375) + b;
}
return c*(7.5625*(t-=(2.625/2.75))*t + 0.984375) + b;
},
bounceBoth: function(t, b, c, d){
if (t < d/2) {
return Tween['bounceIn'](t*2, 0, c, d) * 0.5 + b;
}
return Tween['bounceOut'](t*2-d, 0, c, d) * 0.5 + c*0.5 + b;
}
}
function css(ele, attr, val){
if(typeof attr === 'string' && typeof val === 'undefined'){
if(css3Attr.indexOf(attr) !== -1){
return transform(ele, attr);
}
var ret = getComputedStyle(ele)[attr];
return normalAttr.indexOf(attr) !== -1 ? parseFloat(ret) : ret * 1 === ret * 1 ? ret*1 : ret;
}
function setAttr(attr, val){
if(css3Attr.indexOf(attr) !== -1){
return transform(ele, attr, val);
}
if(normalAttr.indexOf(attr) !== -1){
ele.style[attr] = val ? val + 'px' : val;
}else{
ele.style[attr] = val;
}
}
// 批量设置
if(typeof attr === 'object'){
for(var key in attr){
setAttr(key, attr[key]);
}
return;
}
setAttr(attr, val);
}
function transform(el, attr, val){
el._transform = el._transform || {};
if(typeof val === 'undefined'){
return el._transform[attr];
}
el._transform[attr] = val;
var str = '';
for(var key in el._transform){
var value = el._transform[key];
switch (key) {
case 'translateX':
case 'translateY':
case 'translateZ':
str += `${key}(${value}px) `;
break;
case 'rotate':
case 'rotateX':
case 'rotateY':
case 'skewX':
case 'skewY':
str += `${key}(${value}deg) `;
break;
default:
str += `${key}(${value}) `;
}
}
el.style.transform = str.trim();
}
function mTween(props){
var el = props.el;
if(el.mTween) return;
var duration = props.duration || 400,
fx = props.fx || 'easeOut',
cb = props.cb,
attrs = props.attrs || {};
s = props.s
var beginData = {}, changeData = {};
var maxDis = 0;
for(var key in attrs){
beginData[key] = css(el, key);
changeData[key] = attrs[key] - beginData[key];
maxDis = Math.max(Math.abs(changeData[key]),maxDis);
}
if(typeof duration == "object"){
durationPorps = duration;
duration = durationPorps.multiple!==undefined?maxDis*durationPorps.multiple:maxDis*1.2;
if(durationPorps.min !== undefined){
duration = duration < durationPorps.min?durationPorps.min:duration;
}
if(durationPorps.max !== undefined){
duration = duration > durationPorps.max?durationPorps.max:duration;
}
}
var startTime = Date.now();
(function startMove(){
el.mTween = window.requestAnimationFrame(startMove);
var time = Date.now() - startTime;
if(time > duration){
time = duration;
window.cancelAnimationFrame(el.mTween);
el.mTween = null;
}
for(var key in attrs){
var currentPos = Tween[fx](time, beginData[key], changeData[key], duration,s);
css(el, key, currentPos);
}
if(time === duration && typeof cb === 'function'){
cb.call(el);
}
})();
}
mTween.stop = function (el){
window.cancelAnimationFrame(el.mTween);
el.mTween = null;
};