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>
相关推荐
IT_陈寒2 小时前
Vite的热更新突然不香了,排查三小时差点砸键盘
前端·人工智能·后端
子兮曰2 小时前
Agency-Agents 深度解析:400+ AI 专家的"梦之队"如何重塑开发工作流
前端·后端·vibecoding
山河木马3 小时前
渲染管线-计算得到gl_Position(顶点着色器)之后续GPU流程
javascript·webgl·图形学
竹林8183 小时前
用 The Graph 查询链上数据实战:从手搓 RPC 到 Subgraph,我的 NFT 项目数据加载快了 10 倍
前端·javascript
妙码生花3 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(十九):点选验证码代码逐行目检
前端·后端·go
Awu12274 小时前
⚡从零开发 Agent CLI(五)实现一个可治理、可扩展的工具系统
前端·人工智能·claude
咪库咪库咪4 小时前
Vue3-生命周期
前端
莪_幻尘5 小时前
你的 AI Skill 越多越蠢?Token 上下文爆炸的求生指南
前端·ai编程
lichenyang4535 小时前
从 has.echo 到异步 API 注册表:一次 ASCF API 回调不触发的排查复盘
前端
林瞅瞅5 小时前
Nuxt3 项目部署 Nginx 防盗链后特定 JS 文件 403 问题修复方案
前端