GSAP
Scroll插件:ScrollTrigger、ScrollTo、Observer
SVG插件:MotionPath
UI插件:Flip、Draggable
Text插件:Text
针对其他框架的插件:Easel、Pixi
svg动画
javascript
gsap.to('.ball', {
duration: 3,
repeat: -1,
ease: 'none',
// svg动画
motionPath: {
// path: 'M 10 80 C 80 10, 130 10, 190 80 S 300 150, 360 80', // svg图像的path标签或者path路径值
path: '#motion-path',
align: '#motion-path', // 一般和path保持一致 让目标对象和路径x,y坐标合二为一
autoRotate: true, // 按路径方向自动旋转角度
alignOrigin: [0.5, 0.5], // 一般设置为[0.5, 0.5],即目标对象中心点
// start: 0.3, // 路径动画起点, 默认即0
// end: 0.8, // 路径动画结束点, 默认即1,可以大于1
}
});
gsap的svg动画需要安装插件,gsap有好几个svg插件,其中MotionPath是免费的,其他插件需要付费使用。MotionPath常用的几个属性如上面motionPath所示。更多知识点参考文档即可
时间轴动画
javascript
const tl = gsap.timeline({
repeat: 0,
onComplete: () => {
// 移出时间轴动画元素,重复动画,再重新执行动画
tl
.killTweensOf('.item2')
.repeat(-1)
.restart()
}
})
tl
.to('.item1', {
duration: 0.5,
translateY: 260,
ease: 'bounce.inOut',
})
.to('.item2', {
duration: 0.5,
translateY: 260,
}, '+=0.001')
.to('.item2', {
duration: 0.5,
rotate: 180,
}, '+=0.001')
.to('.item3', {
duration: 0.5,
translateY: 260,
scale: 2
}, '+=0.001')
无缝滚动
如果不需要单步停顿,实现会更容易
javascript
tl = gsap.timeline({
repeat: -1
})
tl
.to('.wrap-inner', {
duration: 12,
ease: 'none',
translateX: `-${scrollWidth}`,
onComplete: () => {
console.log('haha')
}
})
// 单步停顿
tl = gsap.timeline({})
const animeteFuc = () => {
tl
.to('.wrap-inner', {
duration: 3,
ease: 'none',
translateX: `-${scrollWidth}`, // 单步移动的距离
onComplete: () => {
if (scrollIndex >= scrollLength) {
scrollIndex = 1
scrollWidth = itemWidth
// 重置至起始位置
tl
.set('.wrap-inner', {
translateX: 0
})
} else {
scrollIndex += 1
scrollWidth = itemWidth * scrollIndex
}
// 单步停顿的无缝滚动
setTimeout(() => {
animeteFuc()
}, 1000)
}
})
}
animeteFuc()
完整示例
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>gsap单步停顿的无缝滚动</title>
<style>
.wrap {
width: 600px;
height: 200px;
border: 1px solid #333;
margin: 0 auto;
padding: 10px;
box-sizing: border-box;
overflow: hidden;
}
.wrap-inner {
font-size: 0px;
height: 180px;
}
.item {
width: 180px;
height: 180px;
display: inline-block;
font-size: 12px;
color: #fff;
text-align: center;
line-height: 180px;
background-color: burlywood;
margin-right: 10px;
}
</style>
</head>
<body>
<div class="wrap">
<div class="wrap-inner" onmouseenter="onEnter()" onmouseleave="onLeave()">
<div class="item item1">1</div>
<div class="item item2">2</div>
<div class="item item3">3</div>
<div class="item item3">4</div>
<div class="item item1">1</div>
<div class="item item2">2</div>
<div class="item item3">3</div>
<div class="item item3">4</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/gsap.min.js"></script>
<script>
let tl = null
document.addEventListener('DOMContentLoaded', (event) => {
const wrapEl = document.getElementsByClassName('wrap-inner')
const itemEl = document.getElementsByClassName('item')
const rect = itemEl[0].getBoundingClientRect()
const marginEl = window.getComputedStyle(itemEl[0], null)
const itemWidth = rect.width + parseFloat(marginEl.marginLeft) + parseFloat(marginEl.marginRight)
wrapEl[0].style.width = `${itemWidth * itemEl.length}px`
let scrollWidth = itemWidth
let scrollIndex = 1
const scrollLength = itemEl.length / 2
tl = gsap.timeline({})
const animeteFuc = () => {
tl
.to('.wrap-inner', {
duration: 3,
ease: 'none',
translateX: `-${scrollWidth}`,
onComplete: () => {
if (scrollIndex >= scrollLength) {
scrollIndex = 1
scrollWidth = itemWidth
// 重置至起始位置
tl
.set('.wrap-inner', {
translateX: 0
})
} else {
scrollIndex += 1
scrollWidth = itemWidth * scrollIndex
}
// 单步停顿的无缝滚动
setTimeout(() => {
animeteFuc()
}, 1000)
}
})
}
animeteFuc()
});
const onEnter = () => {
tl.pause()
}
const onLeave = () => {
tl.play()
}
</script>
</body>
</html>