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>
相关推荐
去旅行、在路上10 分钟前
chrome使用手机调试触屏web
前端·chrome
Aphasia31139 分钟前
模式验证库——zod
前端·react.js
lexiangqicheng1 小时前
es6+和css3新增的特性有哪些
前端·es6·css3
拉不动的猪2 小时前
都25年啦,还有谁分不清双向绑定原理,响应式原理、v-model实现原理
前端·javascript·vue.js
烛阴2 小时前
Python枚举类Enum超详细入门与进阶全攻略
前端·python
孟孟~2 小时前
npm run dev 报错:Error: error:0308010C:digital envelope routines::unsupported
前端·npm·node.js
孟孟~2 小时前
npm install 报错:npm error: ...node_modules\deasync npm error command failed
前端·npm·node.js
狂炫一碗大米饭2 小时前
一文打通TypeScript 泛型
前端·javascript·typescript
wh_xia_jun3 小时前
在 Spring Boot 中使用 JSP
java·前端·spring boot
二十雨辰3 小时前
[HTML5]快速掌握canvas
前端·html