vue封装gsap自定义动画指令

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>
相关推荐
Juchecar5 分钟前
分析:将现代开源浏览器的JavaScript引擎更换为Python的可行性与操作
前端·javascript·python
极客小俊13 分钟前
Font Awesome 一个基于CSS和LESS的免费图标库工具包
前端
yinuo33 分钟前
CSS基础动画keyframes
前端
一条上岸小咸鱼1 小时前
Kotlin 基本数据类型(一):Numbers
android·前端·kotlin
前端小巷子2 小时前
Vue 事件绑定机制
前端·vue.js·面试
uhakadotcom2 小时前
开源:subdomainpy快速高效的 Python 子域名检测工具
前端·后端·面试
爱加班的猫2 小时前
Node.js 中 require 函数的原理深度解析
前端·node.js
用户8165111263972 小时前
WWDC 2025 Build a SwiftUI app with the new design
前端
伍哥的传说2 小时前
Vue 3.5重磅更新:响应式Props解构,让组件开发更简洁高效
前端·javascript·vue.js·defineprops·vue 3.5·响应式props解构·vue.js新特性