实现一个3D轮播图效果

2,856 阅读5分钟

前言

掘友们好!最近笔者在网上刷到一个3D效果的轮播图,觉得挺有意思,今天跟大家分享一下实现的过程,毕竟轮播图这个玩意在很多场景都会用到,虽然每个组件库都有对应的实现,但是咱作为一名前端也不能只会用,还是得自己会写对吧!笔者实现了三个效果,最终代码只需要稍微改动即可切换成另一种效果。

效果1: CleanShot 2023-08-28 at 20.47.21@2x.png

效果2: CleanShot 2023-08-28 at 20.49.43@2x.png

效果3: CleanShot 2023-08-28 at 20.50.37@2x.png

除了两侧的按钮点击可以切换之外,点击某张图片也可以实现切换。

阅读本文,你将学会:

使用HTMLCSSJavaScript 来实现这个精彩的 3D 轮播图,让你的网页在视觉上更加吸引人。

好了废话不多说,接下来就描述一下笔者实现的思路。

实现3D轮播图

实现思路

咱们来想一下,大致的思路:

  1. 要实现3D的效果,那么肯定要使用CSS动画的3D转换。
  2. 要有多张图片,并且一开始堆叠在一起,然后通过translateX设置X坐标偏移量实现向两侧扩展,通过rotateY设置旋转角度,通过scale设置缩放,通过opacity设置透明度,通过z-index设置层级(光看也许看不出来需要这些属性,但是我们可以通过把一张图片调试成这个样子就能得到)。
  3. 需要有一个变量(index)——当前激活的图片的索引。
  4. 要实现一个函数,用于根据当前的 index 更新图片的style,在这个函数中计算3D转换的相关样式。
  5. 给按钮绑定点击事件,调用第四点的函数即可。
  6. 给多张图片的父节点绑定点击事件,事件委托,点击某张图片时根据event.target拿到点击的哪张图片,然后还是调用第四点的函数。

然后就能实现一个大致的逻辑,如下:

// 当前显示图片的索引
let index = 0

// 多张图片
const imgs = [...document.querySelectorAll('img')]

// 实现切换逻辑
function setStyle(index) {
    // 根据索引计算以下样式
    // translateX 偏移量
    // rotateY 旋转角度
    // scale 缩放
    // opacity 透明度
    // z-index
}

// 图片父节点的点击
function imgContainerClick(e) {
  // 点击的是图片父节点本身,直接return
  if (e.currentTarget === e.target) {
    return
  }
  const index = imgs.indexOf(e.target)
  setStyle(index)
}

// 左右侧按钮点击
function btnClick(type) {
  index = type === 'next' ? index + 1 : index - 1
  // 判断边界
  if(index < 0) return index = 0
  if(index > l - 1) return index = l - 1
  setStyle(index)
}
// 初始化调用一次
setStyle(index)

HTML结构如下

CleanShot 2023-08-28 at 21.38.44@2x.png

style样式如下

CleanShot 2023-08-28 at 21.44.24@2x.png

有了以上的样式就能水平垂直居中,而且让多张图片堆在一起,如下图: CleanShot 2023-08-28 at 21.49.15@2x.png

注意: 这些非关键的样式都很简单,笔者就不过多描述了哦!

接下来就是setStyle的实现。

如何根据 index 计算 translateX

根据观察,不难看出,当前展示的index两侧是对称的一个结构,比如 index = 2(偏移值为0,因为所有图片都堆在一起,偏移值都为0),那么index = 1的图片,就往左侧偏移(偏移值为负数),index = 3的图片就往右侧偏移(偏移值为正数),再加上对称,那么index = 1的偏移值 与 index = 3的偏移值除了符号之外相等,如下图: CleanShot 2023-08-28 at 22.16.55@2x.png

那怎么动态的算这个偏移量呢?

首先,咱们先要设置一个固定的偏移量,比如200,代表每隔一张图片,偏移量加200。其次咱们用遍历图片的索引减去当前显示的index,就能得到两个对称的值。比如index = 2,它的上一张图片索引1减去 index = -1;下一张图片索引 3减去 index = 1;-1 和 1 就是对称的值。那么分别用这个值乘以我们固定的偏移量,就得到了 -200200

const offsetX = 200 // 固定的偏移量
(i - index) * 200 // i 为遍历图片时的索引,index 为当前激活图片的索引

如何根据 index 计算 z-index、opacity、scale

之所以这三个放在一起,因为我们从图中不难看出,这三个属性的值也是对称的,并且index 两侧相等,没有负数(Math.abs(i - index)),笔者是这么算的:

const OPACITY = 0.6 // 固定透明度
const SCALE = 0.8 // 固定缩放
const l = imgs.length // 图片数量
const abs = Math.abs(i - index) // 第 i 张图片与 index 的距离

const zIndex = l - abs // i === index 时 zIndex = l 最大;往两侧递减
const scale = Math.pow(SCALE, abs) // 当abs为0,scale = 1
const opacity = Math.pow(OPACITY, abs) // 当abs为0,opacity = 1

那现在就只剩下最后一个rotateY了。

如何根据 index 计算rotateY

这个属性值的计算与translateX类似,但是我们发现每张图片的旋转角度是一样的,没有随着距离的增大而增大,并且两侧一正一负。

const sign = Math.sign(i - index) // 返回 -1,0,1 中的一个,我们只需要符号,不需要倍率
const rotateY = abs === 0 ? 0 : sign * ROTATE

设置style

最后就是将这些属性设置到img:

img.style = `transform: translateX(${translateX}px) rotateY(${rotateY}deg) scale(${scale});opacity: ${opacity};z-index: ${zIndex};`

到这里你就能得到效果3

怎么得到效果2

.carousel添加样式perspective: 1000px;

关于perspective属性的说明: CleanShot 2023-08-29 at 09.47.42@2x.png

怎么得到效果1

改变一下旋转的角度,比如:

const rotateY = abs === 0 ? 0 : -1 * sign * ROTATE

就能得到效果1了,更多的效果等着你去发现!

最后附上源码: 宽度太小了,展示不全。😂

总结

本文通过使用HTMLCSSJavaScript 实现了 3D 轮播图的效果,分享了完整的实现思路——可能一开始并不知道我们怎么实现这些效果,可以尝试着去控制台试试,可能就有思路了。

如果本文对你有一点点帮助,点个赞支持一下吧,你的每一个【】都是我创作的最大动力 ^_^