之前做官网,设计的交互虽然在其他网站很常见,但是我一时不知道如何实现,直到我看到了gsap,发现原来这么简单。
- demo地址: https://3qmjbvapps2o60q4lto2hwpu4whh0zp1iefvt40hypsf1mxaf9.walrus.site/
- 源码地址:https://github.com/klren0312/gsap-demo
项目搭建
1. 创建vite项目,并安装依赖
# 创建一个原生ts项目
pnpm create vite gsap-demo --template vanilla-ts
cd gsap-demo
# 安装gsap依赖
pnpm add gsap
2. 初始化gsap
import { gsap } from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'
gsap.registerPlugin(ScrollTrigger)
效果一:横向滚动
滚动页面滚动条,gsap会接管滚动条,进行div的横向滚动。
1. 编写html
父组件flex布局,子元素设置三个图片。
<div class="box-container">
<div class="box">
<img class="box-image" src="https://picsum.photos/1200/900" alt="box" />
</div>
<div class="box">
<img class="box-image" src="https://picsum.photos/1200/900" alt="box" />
</div>
<div class="box">
<img class="box-image" src="https://picsum.photos/1200/900" alt="box" />
</div>
</div>
.box-container {
display: flex;
flex-wrap: nowrap;
gap: 20px;
overflow: hidden;
}
.box {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100vh;
flex-shrink: 0;
}
.box-image {
object-fit: cover;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
border-radius: 10px;
}
2. 配置gsap
const boxContainer: HTMLElement | null = document.querySelector('.box-container')
const boxItems = gsap.utils.toArray('.box-container .box')
if (!boxContainer) return
gsap.to(boxItems, {
xPercent: -100 * (boxItems.length - 1),
ease: 'none',
scrollTrigger: {
trigger: boxContainer,
pin: true,
start: 'top top',
scrub: 1,
markers: true,
end: `+=${boxContainer.offsetWidth || 0 - innerWidth}`,
},
})
详细说明:
-
xPercent
: -100 (boxItems.length - 1): 这行代码设置了每个 boxItems 元素的水平移动百分比。xPercent 是一个相对移动的值,-100 (boxItems.length - 1) 意味着将所有的 boxItems 元素水平移动到最后一个元素的位置。 -
ease: 'none'
: 这里设置了动画的缓动效果为“无”,即动画将以线性方式进行,没有加速或减速。 -
scrollTrigger
: 这是 ScrollTrigger 插件的配置对象,用于定义滚动触发的行为。-
trigger: boxContainer
: 指定哪个元素触发滚动动画。 -
pin: true
: 将 boxContainer 固定在视口中,直到动画结束。 -
start: 'top top'
: 定义动画开始的滚动位置,当 boxContainer 的顶部与视口顶部对齐时开始。 -
scrub: 1
: 使动画与滚动同步,值为 1 表示动画的平滑度。 -
markers
: true: 显示滚动触发器的标记,方便调试。 -
end: +=${boxContainer.offsetWidth || 0 - innerWidth}
: 定义动画结束的滚动位置,计算方式是 boxContainer 的宽度减去视口的宽度。这段代码的目的是在用户滚动页面时,创建一个水平滚动的动画效果,使得 boxItems 元素在 boxContainer 内水平移动。
-
3. 查看效果
设置了的start: 'top top'
后,可以看到marker的scroller-start
和scroller-end
都在视口的顶部。
当marker的start
移动到scroller-start
后则开始动画。
当marker的end
移动到scroller-end
后则结束动画
效果二:卡片效果
滚动页面,卡片从右往左展示,类似卡片切换效果。
1. 编写html
绝对定位card,让他们交错排布。
<div class="card-container">
<div class="card card-1">
<img class="card-image" src="https://picsum.photos/400/300" alt="card" />
</div>
<div class="card card-2">
<img class="card-image" src="https://picsum.photos/400/300" alt="card" />
</div>
<div class="card card-3">
<img class="card-image" src="https://picsum.photos/400/300" alt="card" />
</div>
<div class="card card-4">
<img class="card-image" src="https://picsum.photos/400/300" alt="card" />
</div>
<div class="card card-5">
<img class="card-image" src="https://picsum.photos/400/300" alt="card" />
</div>
</div>
.card-container {
position: relative;
display: flex;
flex-wrap: nowrap;
gap: 20px;
overflow: hidden;
width: 100%;
height: 100vh;
}
.card {
width: 400px;
height: 300px;
position: absolute;
top: 50%;
transform: translateY(-50%);
flex-shrink: 0;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
border-radius: 10px;
border: 2px solid #ccc;
overflow: hidden;
}
.card-1 {
right: 10%;
}
.card-2 {
right: 12%;
}
.card-3 {
right: 14%;
}
.card-4 {
right: 16%;
}
.card-5 {
right: 18%;
}
2. 编写gsap动画
const cardContainer: HTMLElement | null = document.querySelector('.card-container')
if (!cardContainer) return
gsap.timeline({
scrollTrigger: {
trigger: cardContainer,
pin: true,
start: 'top top',
scrub: 1,
end: `+=${cardContainer.offsetWidth || 0 - innerWidth}`,
markers: true,
},
})
.to('.card-5', { xPercent: -110, scale: 1.1 }, 0)
.to('.card-5', { xPercent: -250, scale: 1 }, 1)
.to('.card-4', { xPercent: -110, scale: 1.1 }, 1)
.to('.card-4', { xPercent: -250, scale: 1 }, 2)
.to('.card-3', { xPercent: -110, scale: 1.1 }, 2)
.to('.card-3', { xPercent: -250, scale: 1 }, 3)
.to('.card-2', { xPercent: -110, scale: 1.1 }, 3)
.to('.card-2', { xPercent: -250, scale: 1 }, 4)
.to('.card-1', { xPercent: -110, scale: 1.1 }, 4)
.to('.card-1', { xPercent: -250, scale: 1 }, 5)
详细说明:
-
gsap.timeline
: 创建一个时间轴动画,允许多个动画按顺序执行 -
gsap.timeline.to
: 创建每个时间点的动画详情,例如本效果,就是每个卡片向左移动一定百分比和放大缩小效果。
3.查看效果
主要就是最后右边移动到中间并放大,然后移动到最左边缩小到正常大小,每个card依次执行。
总结
主要还是要多看文档,然后通过makers来确定滚动位置是否正确。尤其是结合整个页面时,要保证页面的高度时刻确定的,这样才能让页面加载完毕后,gsap的makers计算正确,比如之前设置了图片懒加载,但是忘了设置图片的高度,导致下面的gsap计算错误,滚动效果出现问题,这个时候就需要开启markers来确定问题。
参考文档
-
gsap.to
: https://gsap.com/docs/v3/GSAP/gsap.to() -
gsap.timeline
: https://gsap.com/docs/v3/GSAP/Timeline -
gsap.timeline.to
: https://gsap.com/docs/v3/GSAP/Timeline/to()