实现一个3D轮播图_3d轮播图特效代码
轮播图大家应该都不陌生了吧,今天我们来实现一个不一样的轮播图。
效果展示
codePen
https://codepen.io/yongtaozheng/pen/pvJogmR
代码实现
html
左右切换按钮
<div class=\"nav-btn prev\" onclick=\"rotate(-1,true)\">❮</div><div class=\"nav-btn next\" onclick=\"rotate(1,true)\">❯</div>
图片容器
<div class=\"spinner\"></div>
底部指示器
<div class=\"indicators\"></div>
css
全局变量与基础布局
:root { --max-width: 180px; /* 图片最大宽度 */ --perspective: 1200px; /* 透视距离,数值越大,3D效果越平缓 */ --radius: 450px; /* 图片环绕的圆半径(控制图片间距和纵深) */}body { display: flex; /* 居中布局 */ min-height: 100vh; /* 占满视口高度 */ background-color: #f0f0f0; /* 背景色 */}
- :root:使用 CSS 变量定义可复用的参数,方便后期修改。
- perspective:设置在父容器上,模拟观看 3D 场景的距离,数值越大,图片变形越小(类似长焦镜头)。
3D 旋转容器
.spinner { transform-style: preserve-3d; /* 子元素保持3D变换 */ transform-origin: 50% 50% calc(-1 * var(--radius)); /* 旋转中心点:水平垂直居中,Z轴负方向radius距离 */ height: 300px; transition: transform 0.8s cubic-bezier(0.23, 1, 0.32, 1); /* 旋转过渡动画, cubic-bezier 定义缓动效果 */}
- transform-origin:设置旋转中心点在容器中心的正后方(Z 轴负方向),使图片围绕一个虚拟的圆心排列。
- transition:使用 cubic-bezier(0.23, 1, 0.32, 1) 实现 “先快后慢” 的弹性效果,让旋转更自然。
图片样式
.spinner img { position: absolute; left: 50%; top: 50%; /* 定位到容器中心 */ width: var(--max-width); transform-origin: 50% 50% calc(-1 * var(--radius)); /* 图片自身的旋转中心点与.spinner一致 */ backface-visibility: hidden; /* 隐藏图片背面,防止旋转时图片翻转显示 */ box-shadow: 0 10px 25px rgba(0,0,0,0.15); /* 投影增强立体感 */}
- backface-visibility: hidden:关键属性!防止图片旋转到背面时出现镜像翻转,确保始终显示正面。
- transform-origin:与父容器 .spinner 的旋转中心一致,确保图片围绕同一圆心排列。
导航按钮和指示器
.nav-btn { background-color: rgba(255,255,255,0.8); /* 半透明背景 */ box-shadow: 0 2px 10px rgba(0,0,0,0.1); /* 悬浮阴影 */ cursor: pointer; z-index: 10; /* 确保按钮在图片上方 */}.indicator { width: 10px; height: 10px; background-color: rgba(0,0,0,0.2); /* 未激活时的指示器样式 */ transition: background-color 0.3s; /* 颜色过渡动画 */}.indicator.active { background-color: rgba(0,0,0,0.6); /* 激活时的指示器样式 */}
功能实现
配置参数
const config = { maxWidth: \"180px\", speed: 1500, // 轮播速度 multiple: 1.2, // 鼠标悬停放大倍数 autoPlay: true, // 是否自动轮播 imgList: [ \"https://img0.baidu.com/it/u=1446729335,4267600834&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500\", \"https://img2.baidu.com/it/u=2922694860,2270800253&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500\", \"https://img0.baidu.com/it/u=595403291,2269048245&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500\", ……………… ],};
- maxWidth:每个图片的最大宽度
- speed:轮播速度,切换的时间频率(ms)
- multiple:鼠标悬停在图片上的时候,图片放大的倍数
- autoPlay:是否开启自动轮播
- imgList:轮播的图片列表
动态创建图片和指示器
根据配置中的图片列表来动态创建图片元素,并设置好旋转角度,根据图片个数创建对于长度的指示器。
config.imgList.forEach((src, index) => { const img = document.createElement(\"img\"); img.src = src; img.dataset.index = index; // 计算每个图片的旋转角度 const rotateAngle = -degreesPerImage * index; img.style.transform = `rotateY(${rotateAngle}deg) translateZ(450px)`; img.addEventListener(\"mouseenter\", handleMouseEnter); img.addEventListener(\"mouseleave\", handleMouseLeave); img.addEventListener(\"click\", () => handleImageClick((totalImages - index) % totalImages) ); spinner.appendChild(img); // 创建指示器 const indicator = document.createElement(\"div\"); indicator.className = \"indicator\" + (index === 0 ? \" active\" : \"\"); indicator.dataset.index = index; indicator.addEventListener(\"click\", () => goToSlide(index)); indicators.appendChild(indicator);});
自动轮播
根据配置信息中的autoPlay
判断是否自动轮播,并在鼠标悬停展示图片的时候停止自动轮播。
function startAutoPlay() { if (mouseHover || !config.autoPlay) return; autoPlayInterval = setInterval(() => { if (!mouseHover) { rotate(1); } }, config.speed);}
停止自动轮播
鼠标悬停展示图片、指示器切换图片、左右按钮切换图片的时候需要停止自动轮播,清除自动轮播的定时器即可。
function stopAutoPlay() { clearInterval(autoPlayInterval); autoPlayInterval = null;}
鼠标移入事件
其实就是图片的hover
效果,在鼠标移入图片的时候放大图片,停止图片自动轮播。
function handleMouseEnter(e) { const img = e.target; img.style.transform = `${img.style.transform} scale(${config.multiple})`; img.style.boxShadow = \"0 15px 30px rgba(0, 0, 0, 0.25)\"; img.style.zIndex = \"10\"; mouseHover = true; stopAutoPlay();}
鼠标离开事件
鼠标移出图片的时候恢复图片原状,并继续自动轮播图片。
function handleMouseLeave(e) { const img = e.target; const rotateAngle = -degreesPerImage * img.dataset.index; img.style.transform = `rotateY(${rotateAngle}deg) translateZ(450px)`; img.style.boxShadow = \"0 10px 25px rgba(0, 0, 0, 0.15)\"; img.style.zIndex = \"1\"; mouseHover = false; startAutoPlay();}
图片点击事件
点击图片的时候停止自动轮播,并将被点击的图片移动到最前面展示。
function handleImageClick(index) { stopAutoPlay(); goToSlide(index);}
图片切换逻辑
function rotate(direction) { const newIndex = (currentIndex + direction + totalImages) % totalImages; // 计算目标索引(处理循环切换) const angleDiff = newIndex - currentIndex; // 选择最短旋转路径(顺时针或逆时针) if (angleDiff > totalImages / 2) angleDiff -= totalImages; if (angleDiff < -totalImages / 2) angleDiff += totalImages; currentIndex = newIndex; angle += angleDiff * degreesPerImage; // 更新总旋转角度 updateSlide(); // 应用旋转}function updateSlide() { spinner.style.transform = `rotateY(${-angle}deg)`; // 旋转容器,图片随之移动 // 更新指示器状态 indicators.querySelectorAll(\".indicator\").forEach((ind, i) => { ind.classList.toggle(\"active\", i === currentIndex); });}
- 最短路径算法:例如 5 张图时,从索引 4 切换到 0,最短路径是逆时针转 72°(而非顺时针转 288°)。
- 负角度旋转:rotateY(${-angle}deg) 确保旋转方向与图片排列方向一致(顺时针切换)。
键盘控制
监听键盘方向键,可以通过左右方向键切换图片。
window.addEventListener(\"keydown\", (e) => { if (e.key === \"ArrowLeft\") rotate(-1, true); if (e.key === \"ArrowRight\") rotate(1, true);});
源码
gitee
https://gitee.com/zheng_yongtao/video-code/tree/master/3D轮播图
github
https://github.com/yongtaozheng/video-code/tree/master/3D轮播图
- 🌟 觉得有帮助的可以点个 star~
- 🖊 有什么问题或错误可以指出,欢迎 pr~
- 📬 有什么想要实现的功能或想法可以联系我~
公众号
关注公众号『 前端也能这么有趣 』,获取更多有趣内容。
发送 加群 还可以加入群聊,一起来学习(摸鱼)吧~
说在后面
🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『
前端也能这么有趣
』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。