手写一个3D轮播图

本文详细介绍了一种基于HTML、CSS和JavaScript实现的3D轮播图制作过程,包括结构搭建、动画设置、指示点样式及点击监听等功能,旨在帮助前端开发者掌握3D轮播图的制作技巧。

源码点击

效果图

在这里插入图片描述

1 搭结构


1.1 基本结构

无论3d还是2d轮播图的结构都是相同的,并引入以写图片

 <section class="wrapper">
  <ul class="carousel">
  	<li><img src="./images/1.jpg" alt=""></li>
  	<li><img src="./images/2.jpg" alt=""></li>
  	<li><img src="./images/3.jpg" alt=""></li>
  	<li><img src="./images/4.jpg" alt=""></li>
  </ul>
 </section>

1.2 通过定位让图片折叠起来


  • 折叠之后最后一张图片在最上面
  • 这里使用了vh单位
  • 开启3d效果
*{
    margin: 0;
    padding: 0;
}
/* 去除滚动条 */
html,body{
    height: 100%;
    overflow: hidden;
}
.wrapper{
    position: relative;
    width: 100%;
    height: 100vh;
}
.carousel{
    height: 100%;
    //开启3d效果
    perspective: 1000px;
    transform-style: preserve-3d;
    li{
        position: absolute;
        left: 0;
        right: 0;
        top: 0;
        bottom: 0;
        img{
            display: block;
            width: 100%;
            height: 100%;
        }
    }
}

2 动画


2.1 分析动画


这个动画可以分为

  • 消失
  • 隐藏

设计到的API

  • 移动translateX
  • 旋转rotateY
  • 缩放scale

我们观察效果图

移动时

消失:动画中:左移40%,动画末:隐藏到z轴200px处
出现:动画中:右移40%


旋转时

消失:动画中:逆时针30deg
出现:动画中:顺时针30deg


缩放

动画中:都缩放0.8


共分为两组

  1. 左移消失的同时,右侧出现
  2. 右侧消失的同时,左侧出现

根据上面的分析,我们写出一下动画

@keyframes leftHide {
    0% {visibility: visible;}
    50%{transform: translateX(-40%) rotateY(30deg) scale(.8);}
    100%{transform: translateZ(-200px);}
}

@keyframes rightShow {
    0% {visibility: hidden; transform: translateZ(-200px);}
    50%{transform: translateX(40%) rotateY(-30deg) scale(.8);}
    100%{}
}					

@keyframes leftShow{
    0%{visibility: hidden;transform: translateZ(-200px);}
    50%{transform: translateX(-40%) rotateY(30deg) scale(.8);}
    100%{}
}

@keyframes rightHide{
    0%{visibility: visible;}
    50%{transform: translateX(40%) rotateY(-30deg) scale(.8);}
    100%{transform: translateZ(-200px);}
}

2.2 使用JS操作动画


这里主要用JS来操作属性,这里有两对四个属性

  • 他们执行的动画,如下所示
// 第一对
.leftShow{visibility: visible;animation:1s leftShow 1 linear;}
.rightHide{visibility: hidden;animation:1s rightHide 1 linear;}
// 第二对
.leftHide{visibility: hidden;animation:1s leftHide 1 linear;}
.rightShow{visibility: visible;animation:1s rightShow 1 linear;}
  • 自动轮播的核心是定时器与活动的样式
const CarliNodes = document.querySelectorAll('.wrapper > .carousel > li')
/* autoIndex 为执行动画的, oldIndex 为同时执行动画的另一张 */
let autoIndex = 0
let oldIndex = 0

setInterval(() => {
	autoIndex++
	/* autoIndex 不能一直增加 */
	if (autoIndex === 4) {
		autoIndex = 0
	}
	CarliNodes[autoIndex].classList.remove('rightHide')
	CarliNodes[autoIndex].classList.remove('leftHide')
	CarliNodes[autoIndex].classList.remove('leftShow')
	CarliNodes[autoIndex].classList.add('rightShow')

	CarliNodes[oldIndex].classList.remove('leftShow')
	CarliNodes[oldIndex].classList.remove('rightHide')
	CarliNodes[oldIndex].classList.remove('rightShow')
	CarliNodes[oldIndex].classList.add('leftHide')

	/* 新执行动画的变成旧的执行动画 */
	oldIndex = autoIndex
}, 2000)

将上面的代码写完后就可以轮播了,但是这个时候有一个缺点,两张图轮播的时候相互折叠,并没有层级(translateZ较大的遮住较小的),这是因为我们的translateZ过于小,景深不够深造成的。

在这里插入图片描述
解决

  1. 将所有的li隐藏,但是我们必须给第一个图片一个样式,这样不会出现空白的情况,<li class="active"><img src="./images/1.jpg" alt=""></li>当我们再次刷新就不会出现空白的情况了
/* 这个样式一定要卸载 leftHide 前面,不然 leftHide 的样式就会被覆盖掉 */
.active{
    visibility: visible;
}
  1. translateZ(-1500px)/perspective: 2000px;

当我们写有关空间的样式的时候一定要注意景深,深度有多少,可以使用直角三角形大致的估计一下,心里就有一个底

优化

  • 我们可以增加以写阴影和圆角,是我们的轮播图更好看些

到这里我们简易版本的3d轮播图大致就写好了

3 指示点


3.1 结构样式


<ul class="indication">
	<li></li>
	<li></li>
	<li></li>
	<li></li>
</ul>
/* 指示点 */
.indication{
    position: absolute;
    left: 50%;
    bottom: 50px;
    display: flex;
    transform: translateX(-50%);
    li{
        width: 60px;
        height: 60px;
        background-color:rgba(0, 0, 0, .5);
        border-radius: 50%;
        margin-right: 15px;
        box-shadow: 0 0 4px rgba(25, 25, 25, 0.8);
        &.active{
            background-color: #000;
        }
    }
}

3.2 动态的样式

我们在定时器内加上

for (let index = 0; index < indicLiNodes.length; index++) {
	indicLiNodes[index].classList.remove('active')				
}

indicLiNodes[autoIndex].classList.add('active')

为了优化效果,我们应该在第一个li标签上加上此样式

<li class="active"></li>

4 点击监听


为每个按钮绑定点击监听,绑定之前一定要先清楚定时器

for (let index = 0; index < indicLiNodes.length; index++) {
	const element = indicLiNodes[index];
	/* 指示点样式 */
	element.onclick = function () {
		console.log('click')
		clearInterval(setIntervalId)
		for (let index = 0; index < indicLiNodes.length; index++) {
			indicLiNodes[index].classList.remove('active')
		}
		this.classList.add('active')
	}

4.1 方向判断


这里有两种情况,把这种判断写在点击监听函数内

/* 轮播图跳转 */
if (index > oldIndex) {
	CarliNodes[index].classList.remove('rightHide')
	CarliNodes[index].classList.remove('leftHide')
	CarliNodes[index].classList.remove('leftShow')
	CarliNodes[index].classList.add('rightShow')

	CarliNodes[oldIndex].classList.remove('leftShow')
	CarliNodes[oldIndex].classList.remove('rightHide')
	CarliNodes[oldIndex].classList.remove('rightShow')
	CarliNodes[oldIndex].classList.add('leftHide')
}
if (index < oldIndex) {
	CarliNodes[index].classList.remove('rightHide')
	CarliNodes[index].classList.remove('leftHide')
	CarliNodes[index].classList.remove('rightShow')
	CarliNodes[index].classList.add('leftShow')

	CarliNodes[oldIndex].classList.remove('leftHide')
	CarliNodes[oldIndex].classList.remove('leftShow')
	CarliNodes[oldIndex].classList.remove('rightShow')
	CarliNodes[oldIndex].classList.add('rightHide')
}
oldIndex = index
autoIndex = index

我们就实现了点击翻转到相应的图片

5 鼠标移入效果


当鼠标移入轮播图时,不再轮播,移除轮播图示再次轮播

  • 这个效果其实挺简单,当我们鼠标移入是清楚定时器
  • 鼠标移除是,再次运行轮播函数

所以这里要求我们要将轮播代码分装成一个函数

/* 将轮播图代码封装成一个函数 */
carouselPlay()
function carouselPlay() {
	/* 在开启定时器之前清除定时器 */
	clearInterval(setIntervalId)
	setIntervalId = setInterval(() => {
		console.log(autoIndex)
		autoIndex++
		/* autoIndex 不能一直增加 */
		if (autoIndex === CarliNodes.length) {
			autoIndex = 0
		}

		for (let index = 0; index < indicLiNodes.length; index++) {
			indicLiNodes[index].classList.remove('active')
		}

		indicLiNodes[autoIndex].classList.add('active')

		CarliNodes[autoIndex].classList.remove('leftShow')
		CarliNodes[autoIndex].classList.remove('leftHide')
		CarliNodes[autoIndex].classList.remove('rightHide')
		CarliNodes[autoIndex].classList.add('rightShow')

		CarliNodes[oldIndex].classList.remove('leftShow')
		CarliNodes[oldIndex].classList.remove('rightShow')
		CarliNodes[oldIndex].classList.remove('rightHide')
		CarliNodes[oldIndex].classList.add('leftHide')
		/* 新执行动画的变成旧的执行动画 */
		oldIndex = autoIndex
		/* 定时器时间 - 执行动画使劲啊 = 照片停留时间 */
	}, 4000)
}

鼠标移入效果

主要是为ul绑定鼠标移入移出事件

carouselNode.onmouseenter = function () {
	clearInterval(setIntervalId)
}
carouselNode.onmouseleave = function () {
	carouselPlay()
}

6 优化


6.1 鼠标指针的优化


可点指示点鼠标移入是手,不可点击时箭头

 li{
     width: 60px;
     height: 60px;
     background-color:rgba(225, 225, 225, .5);
     border-radius: 50%;
     margin-right: 15px;
     box-shadow: 0 0 4px rgba(25, 25, 25, 0.8);
cursor: pointer;
     &.active{
         background-color: #fff;
		/* 改变鼠标指针 */
		cursor: default;
     }
 }
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值