原生js实现3D照片墙

聊一下心得: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代码:用到了我昨天在博客上写的工具函数:https://blog.csdn.net/lhjuejiang/article/details/80896428

提供主要的实现步骤的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)`;
        });
    }
    
})()

猜你喜欢

转载自blog.csdn.net/lhjuejiang/article/details/80918946