1、指令文件封装
javascript
import { gsap } from 'gsap';
// 动画类型配置
const ANIMATION_TYPES = {
// 缩放
scale: {
from: { scale: 0.5, opacity: 0 },
to: { scale: 1, opacity: 1 },
hide: { scale: 0.5, opacity: 0 },
},
// 透明度
fade: {
from: { opacity: 0 },
to: { opacity: 1, ease: 'sine.out' },
hide: { opacity: 0, ease: 'sine.in' },
},
// 向上滑出
slideUp: {
from: { y: 50, opacity: 0 },
to: { y: 0, opacity: 1, ease: 'power2.out' },
hide: { y: 50, opacity: 0, ease: 'power2.in' },
},
// 向下滑出
slideDown: {
from: { y: -50, opacity: 0 },
to: { y: 0, opacity: 1, ease: 'power2.out' },
hide: { y: -50, opacity: 0, ease: 'power2.in' },
},
// 向左滑出
slideLeft: {
from: { x: 50, opacity: 0 },
to: { x: 0, opacity: 1, ease: 'power2.out' },
hide: { x: 50, opacity: 0, ease: 'power2.in' },
},
// 向右滑出
slideRight: {
from: { x: -50, opacity: 0 },
to: { x: 0, opacity: 1, ease: 'power2.out' },
hide: { x: -50, opacity: 0, ease: 'power2.in' },
},
// 弹窗
bounce: {
from: { y: -100, opacity: 0 },
to: {
y: 0,
opacity: 1,
ease: 'bounce.out',
duration: 1.5,
},
hide: {
y: 100,
opacity: 0,
ease: 'power2.in',
duration: 0.5,
},
},
// 翻转折叠
flip: {
from: { rotationY: 90, opacity: 0 },
to: { rotationY: 0, opacity: 1, ease: 'power2.out' },
hide: { rotationY: -90, opacity: 0, ease: 'power2.in' },
},
};
// 默认配置
const DEFAULT_CONFIG = {
type: 'scale',
duration: 0.3,
delay: 0,
origin: 'center',
onComplete: null,
onStart: null,
};
export const vGsapAnimation = {
mounted(el, binding) {
// 合并默认配置和绑定值
const config = {
...DEFAULT_CONFIG,
...(typeof binding.value === 'object' ? binding.value : { value: binding.value }),
};
// 获取动画配置
const animationConfig = ANIMATION_TYPES[config.type] || ANIMATION_TYPES.scale;
// 设置变换原点
el.style.transformOrigin = config.origin;
el.style.willChange = 'transform, opacity';
// 保存配置到元素
el._gsapConfig = config;
// 初始化动画时间轴
el._gsapTimeline = gsap.timeline({
paused: true,
onComplete: config.onComplete,
onStart: config.onStart,
});
// 创建显示动画
el._gsapTimeline.fromTo(el, animationConfig.from, {
...animationConfig.to,
duration: config.duration,
delay: config.delay,
});
// 初始状态
if (config.value !== false) {
el.style.visibility = 'visible';
el._gsapTimeline.play();
} else {
el.style.visibility = 'hidden';
gsap.set(el, animationConfig.from);
}
},
updated(el, binding) {
const oldConfig = el._gsapConfig;
const newConfig = {
...DEFAULT_CONFIG,
...(typeof binding.value === 'object' ? binding.value : { value: binding.value }),
};
// 如果配置有变化
if (JSON.stringify(oldConfig) !== JSON.stringify(newConfig)) {
// 更新配置
el._gsapConfig = newConfig;
// 获取动画配置
const animationConfig = ANIMATION_TYPES[newConfig.type] || ANIMATION_TYPES.scale;
// 更新时间轴回调
el._gsapTimeline.eventCallback('onComplete', newConfig.onComplete);
el._gsapTimeline.eventCallback('onStart', newConfig.onStart);
if (newConfig.value !== oldConfig?.value) {
if (newConfig.value === false) {
// 隐藏动画
gsap.to(el, {
...animationConfig.hide,
duration: newConfig.duration,
delay: newConfig.delay,
onComplete: () => {
el.style.visibility = 'hidden';
},
});
} else {
// 显示动画
el.style.visibility = 'visible';
el._gsapTimeline.restart();
}
}
}
},
unmounted(el) {
// 清理动画
if (el._gsapTimeline) {
el._gsapTimeline.kill();
}
},
};
2、main.ts注册
javascript
// 引入文件
import { vGsapAnimation } from 'xxx'
// 注册指令
app.directive('gsap', vGsapAnimation)
3、使用
- 基本使用
html
<div v-gsap="isVisible">内容</div>
- 指定动画类型
html
<div v-gsap="{ type: 'fade', value: isVisible }">内容</div>
- 完整配
html
<div v-gsap="{
type: 'bounce',
value: isVisible,
duration: 1,
delay: 0.2,
origin: 'top left',
onComplete: handleComplete
}">内容</div>