js实现3D照片墙效果


Posted in Javascript onOctober 28, 2019

聊一下心得:CSS写得好,真的可以省很多js代码哈,写起来也简单很多,所以要好好掌握js哈,所以这里也提供了css代码,如果您觉得您的css写得不错,可以直接看js代码哦

效果:

1、点击Start View进入照片墙

2、只有一张图片是在中间显示,其他图片在中间的图片两侧随机排序,并且随机旋转一定的角度,层级也是随机的哦

3、点击上面的导航条,可以让对应的图片在中间显示

4、点击中间的图片该照片翻转,显示背面(照片的描述信息)

实现过程:

1、用数据生成结构(模拟的数据,此处不再提供)

2、对所有图片进行排序

3、计算两侧图片的随机范围

4、控制图片翻转

5、控制导航按钮切换图片

6、遮罩层动画实现

HTML代码:

<body>
 <div class="photo_wall">
 <div class="photo">
 <!-- 每张图片的最外层,用来控制图片的旋转和位移 -->
 <div class="photo_i front" id="photo_{{id}}">
 <!-- 内层用来控制图片的3D翻转 -->
 <div class="photo_3d">
 <!-- 每个照片的正面 -->
 <div class="photo_side photo_front">
 <p><img {{src}}="{{img}}"></p>
 <h3>{{caption}}</h3>
 </div>
 <!-- 每个照片的反面 -->
 <div class="photo_side photo_back">
 <p class="desc">{{desc}}</p>
 </div>
 </div>
 </div>
 {{split}}
 <div class="nav"><span class="nav_i" id="nav_{{id}}">?</span></div>
 </div>
 <div class="shade">
 <div class="start">Start View</div>
 </div>
 </div>
</body>

CSS代码:

/*最外层样式*/
.photo_wall{
 width: 100%;
 height: 600px;
 position: relative;
 background: url(../imgs/bg.jpg) no-repeat center center;
 background-size: cover;
 overflow: hidden;
}
 
/*照片区域的样式*/
.photo {
 position: absolute;
 left: 0;
 top: 0;
 width: 100%;
 height: 100%;
 z-index: 1;
 opacity: 0;
 transition: 1s;
}
 
/*每个照片的样式*/
.photo .photo_i,.photo .photo_3d,.photo .photo_side {
 width: 336px;
 height: 392px;
 position: absolute;
 left: 0;
 top: 0;
}
 
.photo .photo_i {
 transition: 800ms;
 perspective: 750px;
 left: 50%;
 top: 50%;
 transform: translate(-50%,-50%) scale(.5) rotate(0);
}
 
.photo .photo_3d {
 transition: 500ms;
 transform-style: preserve-3d;
 transform-origin: 0 50%;
}
/*正面和反面的公共样式*/
.photo .photo_side {
 border-radius: 6px;
 background: #fff;
 padding: 26px 24px;
 box-sizing: border-box;
 backface-visibility: hidden;
}
 
/*照片的正面样式*/
.photo .photo_front {
 transform: rotateY(0);
}
.photo .photo_front p {
 width: 286px;
 height: 286px;
 border: 2px solid #d8536d;
 overflow: hidden;
 display: flex;
 /*align-items: center;*/
}
.photo .photo_front p img{
 width: 100%;
 align-self: center;
}
.photo .photo_front h3{
 width: 166px;
 height: 44px;
 background: #d8536d;
 border-radius: 0 0 6px 6px;
 margin: 0 auto;
 text-align: center;
 font: 16px/44px Arial;
 color: #fff;
}
/*照片的反面样式*/
.photo .photo_back {
 transform: rotateY(-180deg);
}
 
.photo .photo_back .desc {
 font-size: 14px;
 line-height: 20px;
 color: #d8536d;
}
.photo .photo_back a {
 color: #d8356d;
}
/*照片的居中样式*/
.photo .center {
 z-index: 9999;
 left: 50%;
 top: 50%;
 transform: translate(-50%,-50%) scale(1) rotate(0);
}
 
/*照片正面的class*/
.photo .front .photo_3d {
 transform: translateX(0) rotateY(0);
}
/*照片反面的calss*/
.photo .back .photo_3d {
 transform: translateX(100%) rotateY(-180deg);
}
 
/*导航栏的样式*/
.nav {
 position: absolute;
 left: 0;
 top: 0;
 z-index: 888;
 width: 100%;
 height: 200px;
 padding-top: 10px;
 box-sizing: border-box;
 text-align: center;
 background: -webkit-linear-gradient(top,rgba(0,0,0,.5),transparent);
}
 
@font-face {
 font-family: "icont";
 src: url(../font/iconfont.woff) format("woff");
}
 
.nav .nav_i {
 display: inline-block;
 width: 30px;
 height: 30px;
 border-radius: 50%;
 background: rgba(255,255,255,.5);
 font-family: "icont";
 text-align: center;
 line-height: 30px;
 color: rgba(255,255,255,0);
 cursor: pointer;
 transform: scale(.5);
 transition: 500ms;
}
 
.nav .active {
 color: rgba(255,255,255,1);
 transform: scale(.9) rotateY(0);
}
 
.nav .back {
 transform: scale(.8) rotateY(-180deg);
}
 
/*遮罩层*/
.photo_wall .shade {
 position: absolute;
 left: 0;
 top: 0;
 z-index: 2;
 width: 100%;
 height: 100%;
 background: rgba(255,255,255,.7);
 display: flex;
 justify-content: center;
 align-items: center;
}
.photo_wall .hide {
 transition: 1s;
 opacity: 0;
 transform: scale(0) rotateY(360deg);
}
.photo_wall .shade .start {
 width: 200px;
 height: 60px;
 border: 2px solid #d8536d;
 border-radius: 10px;
 background: rgba(248,229,227,.5);
 text-align: center;
 font: 22px/60px Arial;
 cursor: pointer;
}

js代码:用到了我昨天在博客上写的工具函数:

// 用来获取元素
// 用来判断某个元素是否有某个class
// 如果没有添加
// 如果有就删除
 
//获取元素id class tag all
function M(sele) {
 var first = sele.substr(0,1),
 isArr = sele.split(' ');//id class tag
 if(first==="#"&&isArr.length==1){//id
 return document.getElementById(sele.substr(1));
 }else{
 var arr = Array.from(document.querySelectorAll(sele));
 return arr.length == 1?arr[0] :arr;
 }
}
 
//判断某个元素是否包含某个class
function hasClass(obj,cls){
 var re = new RegExp(`\\b${cls}\\b`);
 if(re.test(obj.className)){
 return true;
 }else{
 return false;
 }
}
 
//给某个元素添加class
function addClass(obj,cls){
 if(!hasClass(obj,cls)){
 obj.className += ` ${cls}`;//不要忘了前面的空格哈
 }
 obj.className = obj.className.trim();//去掉前后空格
}
 
//给某个元素删除class
function rmClass(obj,cls){
 var re = new RegExp(`\\b${cls}\\b`);
 if(hasClass(obj,cls)){
 obj.className = obj.className.replace(re,'')
  .replace(/\s{2}/,' ').trim();//去掉前后空格
 }
}

提供主要的实现步骤的js代码:

(function () {
 
//---------------------------------------------------------
// 初始化数据
 var data = dataList,len = data.length;
 
 createPhotos(data);
 
 var n = 0;
 
//---------------------------------------------------------
// 基本逻辑
 M('.shade .start').addEventListener('click',function() {
 addClass(M('.shade'),'hide');
 M('.photo').style.opacity = 1;
 addClass(M(`#photo_0`),'center');
 setTimeout(function(){
  sortImgs(n);
 }, 200);
 });
 
 M('.nav_i').forEach((item,i)=>{
 item.onclick = function(){
  turnImg(M(`#photo_${i}`));
 };
 });
 
//---------------------------------------------------------
// 需求函数化
 
// 需求1:利用数据生成所有html结构
 function createPhotos(data) {
 var photo_html = M('.photo').innerHTML.split('{{split}}')[0].trim(),
  nav_html = M('.nav').innerHTML.trim();
 
 var photos = [],nav = [];
 
 data.forEach((item,i)=>{
  var photoTemp = photo_html.replace(/{{id}}/,i)
     .replace(/{{src}}/,'src')
     .replace(/{{img}}/,item.img)
     .replace(/{{caption}}/,item.caption)
     .replace(/{{desc}}/,item.desc),
  navTemp = nav_html.replace(/{{id}}/,i);
 
  photos.push(photoTemp);
  nav.push(navTemp);
 });
 photos.push(`<div class="nav">${nav.join('')}</div>`);
 M('.photo').innerHTML = photos.join('');
 }
 
 // 需求2:给所有的图片排序
 function sortImgs(n) {
 var photos = M('.photo_i');
 
 initPhotos(photos);
 
 var center = photos.splice(n,1)[0];
 addClass(center,'center');
 addClass(M(`#nav_${n}`),'active');
 
 // center.addEventListener('click', function(e){
 // turnImg(this);
 // });
 
 center.onclick = function () {
  turnImg(this);
 };
 
 // 对剩余的图片进行随机排序
 photos.sort(()=>{
  return 0.5 - Math.random();
 })
 
 
 var rP = scope(); //返回左右两侧范围 从 x - y
 
 // 分成左侧和右侧两部分
 var left = photos.splice(0,Math.ceil((len-1)/2)),
  right = photos;
 
 left.forEach((item,i)=>{
  item.style.zIndex = rn([0,len]);
  item.style.left = rn(rP.L.x) + 'px';
  item.style.top = rn(rP.L.y) + 'px';
  item.style.transform = `translate(0,0) scale(.9) rotate(${rn([-2160,2160])}deg)`;
 });
 right.forEach((item,i)=>{
  item.style.zIndex = rn([0,len]);
  item.style.left = rn(rP.R.x) + 'px';
  item.style.top = rn(rP.R.y) + 'px';
  item.style.transform = `translate(0,0) scale(.9) rotate(${rn([-2160,2160])}deg)`;
 });
 }
 
 // 需求3 编写某个区间的随机整数
 function rn(arr) {
 var max = Math.max.apply(null,arr),
  min = Math.min.apply(null,arr);
 var p = Math.round(Math.random() * (max - min) + min);
 //?;
 return p;
 }
 
 // 需求4 计算随机的范围
 function scope() {
 var outer = M('.photo_wall');
 var pic = M(`#photo_${rn([0,len-1])}`);
 var W = outer.clientWidth,
  H = outer.clientHeight,
  w = pic.offsetWidth,
  h = pic.offsetHeight;
  console.log(W,w);
 var data = {
  L:{
  x:[-w/3,W/2 - w/2 - w],
  y:[-h/3,H - h*2/3]
  },
  R:{
  x:[W/2 + w/2,W - w*2/3],
  y:[-h/3,H - h*2/3]
 
  }
 }
 return data;
 }
 
 // 需求5:控制图片翻转
 function turnImg(ele) {
 var cur = ele.id.split('_')[1];
 var nav = M(`#nav_${cur}`);
 
 if(!hasClass(ele,'center')){ //如果点的不是当前对应的按钮就重新排序
  return sortImgs(cur)
 }
 
 if(hasClass(ele,'front')){
  //翻转到背面
  console.log('现在是正面准备移除front');
  addClass(ele,'back');
  console.log(ele.className);
  rmClass(ele,'front');
  console.log(ele.className);
  addClass(nav,'back');
 }else{
  //翻转到正面
  console.log('现在是反面准备移除back');
  addClass(ele,'front');
  console.log(ele.className);
  rmClass(ele,'back');
  console.log(ele.className);
  rmClass(nav,'back')
 }
 }
 
 // 需求6 初始化所有样式
 function initPhotos(objs) {
 objs.forEach((item,i)=>{
  if(hasClass(item,'center')){
  var nav = M(`#nav_${i}`);
  rmClass(item,'center');
  rmClass(item,'back');
  addClass(item,'front');
  rmClass(nav,'active');
  rmClass(nav,'back');
  item.onclick = null;
  }
  item.style.left = '';
  item.style.top = '';
  item.style.zIndex = '';
  item.style.transform = `translate(-50%,-50%) scale(1.1) rotate(0deg)`;
 });
 }
 
})()

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
利用WebBrowser彻底解决Web打印问题(包括后台打印)
Jun 22 Javascript
JSON 和 JavaScript eval使用说明
Jun 13 Javascript
使用基于jquery的gamequery插件做JS乒乓球游戏
Jul 31 Javascript
引用外部脚本时script标签关闭的写法
Jan 20 Javascript
jQuery filter函数使用方法
May 19 Javascript
简单方法判断JavaScript对象为null或者属性为空
Sep 26 Javascript
js实现页面跳转的五种方法推荐
Mar 10 Javascript
Vue自定义指令拖拽功能示例
Feb 17 Javascript
jQuery Validate插件ajax方式验证输入值的实例
Dec 21 jQuery
vue使用ajax获取后台数据进行显示的示例
Aug 09 Javascript
js模拟实现烟花特效
Mar 10 Javascript
JavaScript实现10秒后再次获取验证码
Dec 02 Javascript
vue+webpack 更换主题N种方案优劣分析
Oct 28 #Javascript
使用Vue调取接口,并渲染数据的示例代码
Oct 28 #Javascript
JavaScript 反射和属性赋值实例解析
Oct 28 #Javascript
vue 解决数组赋值无法渲染在页面的问题
Oct 28 #Javascript
在vue中把含有html标签转为html渲染页面的实例
Oct 28 #Javascript
详解关闭令人抓狂的ESlint 语法检测配置方法
Oct 28 #Javascript
Vue实现将数据库中带html标签的内容输出(原始HTML(Raw HTML))
Oct 28 #Javascript
You might like
实例(Smarty+FCKeditor新闻系统)
2007/01/02 PHP
国产PHP开发框架myqee新手快速入门教程
2014/07/14 PHP
使用php的HTTP请求的库Requests实现美女图片墙
2015/02/22 PHP
PHP快速生成各种信息提示框的方法
2016/02/03 PHP
将nodejs打包工具整合到鼠标右键的方法
2013/05/11 NodeJs
js获取url中的参数且参数为中文时通过js解码
2014/03/19 Javascript
JavaScript格式化日期时间的方法和自定义格式化函数示例
2014/04/04 Javascript
两种不同的方法实现js对checkbox进行全选和反选
2014/05/13 Javascript
nodejs 子进程正确的打开方式
2017/07/03 NodeJs
AjaxUpLoad.js实现文件上传
2018/03/05 Javascript
AngularJS标签页tab选项卡切换功能经典实例详解
2018/05/16 Javascript
Vue官方推荐AJAX组件axios.js使用方法详解与API
2018/10/09 Javascript
微信小程序实现星星评价效果
2018/11/02 Javascript
JavaScript继承的特性与实践应用深入详解
2018/12/30 Javascript
jQuery实现的网站banner图片无缝轮播效果完整实例
2019/01/28 jQuery
如何构建 vue-ssr 项目的方法步骤
2020/08/04 Javascript
[32:26]EG vs IG 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
python+Django+apache的配置方法详解
2016/06/01 Python
Python分治法定义与应用实例详解
2017/07/28 Python
python的unittest测试类代码实例
2017/12/07 Python
python交易记录整合交易类详解
2019/07/03 Python
python实现扑克牌交互式界面发牌程序
2020/04/22 Python
Java基础面试题
2014/07/19 面试题
大专生自我鉴定范文
2013/10/01 职场文书
机械绘图员岗位职责
2013/11/19 职场文书
办公室前台的岗位职责
2013/12/20 职场文书
信息总监管理职责范本
2014/03/08 职场文书
职务聘任书范文
2014/03/29 职场文书
合伙经营协议书范本
2014/09/13 职场文书
党的群众路线教育实践活动剖析材料
2014/09/30 职场文书
离婚案件上诉状
2015/05/23 职场文书
安娜卡列尼娜观后感
2015/06/11 职场文书
实习感想范文
2015/08/10 职场文书
幼儿园保教工作总结2015
2015/10/15 职场文书
详细介绍python操作RabbitMq
2022/04/12 Python
Go gorilla/sessions库安装使用
2022/08/14 Golang