1、指令文件封装
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注册
// 引入文件
import { vGsapAnimation } from 'xxx'// 注册指令
app.directive('gsap', vGsapAnimation)
3、使用
- 基本使用
<div v-gsap="isVisible">内容</div>
- 指定动画类型
<div v-gsap="{ type: 'fade', value: isVisible }">内容</div>
- 完整配
<div v-gsap="{type: 'bounce',value: isVisible,duration: 1,delay: 0.2,origin: 'top left',onComplete: handleComplete
}">内容</div>