vue 3d轮播图demo

 佚名文
发布时间:2025-06-21 15:09

根据 vuetelemetry 官网轮播图的效果复现,在大致有几个需求:

点击非中央轮播图,图片滑动。

点击中央轮播图触发该轮播图事件(比如弹窗)。

图片滑动有惯性(先慢后快),且背景(上一张轮播图)有缩放变大效果。

实现gsap 介绍

先简单介绍一下 gsap 的动画函数(官方文档):

// 将一个或多个元素 targets 在指定时间 second 内按一定的速率函数变化至某个指定的 options 状态 (targets, second, options)

例子:

(".box", 1, {rotation: 27, x: 100});

↑ 将所有含 .box 类的元素在 1 秒内变化至 transform: translate(100px, 0px) rotate(27deg); 的状态。

核心动画逻辑

在一个含图片 img 的 div 中,靠后的节点会优先显示在上层,也就是我们只需拷贝一个新的包含图片的 div 到原 div 同级即可。

// 在视图中后面,在 node 中前面的节点 const beforeNode = reverse ? slideLeft : slideRight; // 在视图中前面,在 node 中后面的节点 const afterNode = reverse ? slideRight : slideLeft; const afterNodeCopy = afterNode.cloneNode(true); afterNodeCopy.style.transform = reverse ? "translateX(100%)" : "translateX(-100%)"; beforeNode.parentNode.appendChild(afterNodeCopy); (afterNodeCopy, 1, { xPercent: reverse ? -100 : 100, ease: "expo.inOut", onStart: function() { _this.noDrag(); (beforeNode, 1, { scale: 1.15, ease: "expo.inOut", }); }, onComplete: function() { beforeNode.parentNode.removeChild(beforeNode); afterNodeCopy.style.transform = ""; }, });

下面详解这段代码:

// 在视图中后面,在 node 中前面的节点 const beforeNode = reverse ? slideLeft : slideRight; // 在视图中前面,在 node 中后面的节点 const afterNode = reverse ? slideRight : slideLeft; const afterNodeCopy = afterNode.cloneNode(true);

↑ 我们事先根据正逆向 reverse 做不同的分辨,从而选择好需要在前和在后的包含 img 的 div 节点,并做拷贝。

afterNodeCopy.style.transform = reverse ? "translateX(100%)" : "translateX(-100%)"; beforeNode.parentNode.appendChild(afterNodeCopy);

↑ 对于在后的节点(也就是显示在上层),做水平 100% 的平移,并添加入目标 div 同级位置。

(afterNodeCopy, 1, { xPercent: reverse ? -100 : 100, ease: "expo.inOut", onStart: function() { _this.noDrag(); (beforeNode, 1, { scale: 1.15, ease: "expo.inOut", }); }, onComplete: function() { beforeNode.parentNode.removeChild(beforeNode); afterNodeCopy.style.transform = ""; }, });

执行动画函数,在 1 秒内从原位置以 ease: "expo.inOut" 的动画速率函数,过渡到水平平移 xPercent: 100 的末状态,在启动函数时对背景(此处的前节点)做同速率函数的缩放。

动画完成时,清除前置节点(显示在后层的原节点),并清除新进入的后节点上面的样式。

全局锁

每个动画函数执行时是异步的,为了保证所有节点都完成,需要建立 Promise 进行统一管理:

// 动画执行核心函数 animation(slideLeft, slideRight, reverse) { return new Promise((resolve, reject) => { (afterNodeCopy, 1, { ...... }, onComplete: function() { ...... resolve(); }, }); } }

最后使用 Promise.all() 统一管理全局锁。

取消图片可拖动

noDrag() { document.getElementsByTagName("img").forEach((item) => { item.onmousedown = (e) => { e.preventDefault(); }; }); }

原生 js 禁止所有 img 的拖动,并在页面加载后和动画开始执行时各执行一次(此时新节点被加入,要取消该节点可拖动)。

总结

完整代码较多,已经封装为组件,详见:

fz6m / vue-gsap-slider-wapper

首页
评论
分享
Top