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>
?
????????