miniprogramme/components/page-transition/page-transition.js
2025-09-12 16:08:17 +08:00

456 lines
10 KiB
JavaScript

// 🎬 页面过渡组件逻辑
const animationManager = require('../../utils/animation-manager.js');
Component({
properties: {
// 过渡类型
transitionType: {
type: String,
value: 'fade',
observer: 'onTransitionTypeChange'
},
// 是否显示
visible: {
type: Boolean,
value: true,
observer: 'onVisibleChange'
},
// 动画时长
duration: {
type: Number,
value: 300
},
// 缓动函数
easing: {
type: String,
value: 'ease-out'
},
// 是否显示遮罩
showOverlay: {
type: Boolean,
value: false
},
// 遮罩类型
overlayType: {
type: String,
value: 'fade-black'
},
// 是否显示加载
showLoading: {
type: Boolean,
value: false
},
// 加载文本
loadingText: {
type: String,
value: '加载中...'
},
// 是否启用硬件加速
hardwareAccelerated: {
type: Boolean,
value: true
},
// 调试模式
debug: {
type: Boolean,
value: false
}
},
data: {
// 过渡状态
transitionState: 'idle', // idle, entering, entered, leaving, left
// 动画数据
animationData: null,
loadingAnimation: null,
// 样式
animationStyle: '',
overlayStyle: '',
// CSS类
transitionClass: '',
overlayClass: ''
},
lifetimes: {
attached() {
console.log('🎬 页面过渡组件加载');
this.initComponent();
},
ready() {
console.log('🎬 页面过渡组件就绪');
this.setupInitialState();
},
detached() {
console.log('🎬 页面过渡组件卸载');
this.cleanup();
}
},
methods: {
// 初始化组件
initComponent() {
// 设置初始过渡类
this.updateTransitionClass();
// 设置遮罩类
this.updateOverlayClass();
// 创建加载动画
this.createLoadingAnimation();
},
// 设置初始状态
setupInitialState() {
if (this.properties.visible) {
this.enter();
} else {
this.setData({
transitionState: 'left'
});
}
},
// 过渡类型变化处理
onTransitionTypeChange(newType, oldType) {
if (newType !== oldType) {
this.updateTransitionClass();
}
},
// 可见性变化处理
onVisibleChange(visible, wasVisible) {
if (visible === wasVisible) return;
if (visible) {
this.enter();
} else {
this.leave();
}
},
// 🎭 ===== 过渡控制 =====
// 进入动画
async enter() {
if (this.data.transitionState === 'entering' || this.data.transitionState === 'entered') {
return;
}
console.log('🎬 开始进入动画:', this.properties.transitionType);
this.setData({
transitionState: 'entering'
});
this.triggerEvent('transitionstart', {
type: 'enter',
transitionType: this.properties.transitionType
});
try {
// 创建进入动画
const animation = this.createEnterAnimation();
this.setData({
animationData: animation.export()
});
// 等待动画完成
await this.waitForAnimation();
this.setData({
transitionState: 'entered'
});
this.triggerEvent('transitionend', {
type: 'enter',
transitionType: this.properties.transitionType
});
console.log('✅ 进入动画完成');
} catch (error) {
console.error('❌ 进入动画失败:', error);
this.setData({
transitionState: 'entered'
});
}
},
// 退出动画
async leave() {
if (this.data.transitionState === 'leaving' || this.data.transitionState === 'left') {
return;
}
console.log('🎬 开始退出动画:', this.properties.transitionType);
this.setData({
transitionState: 'leaving'
});
this.triggerEvent('transitionstart', {
type: 'leave',
transitionType: this.properties.transitionType
});
try {
// 创建退出动画
const animation = this.createLeaveAnimation();
this.setData({
animationData: animation.export()
});
// 等待动画完成
await this.waitForAnimation();
this.setData({
transitionState: 'left'
});
this.triggerEvent('transitionend', {
type: 'leave',
transitionType: this.properties.transitionType
});
console.log('✅ 退出动画完成');
} catch (error) {
console.error('❌ 退出动画失败:', error);
this.setData({
transitionState: 'left'
});
}
},
// 🎨 ===== 动画创建 =====
// 创建进入动画
createEnterAnimation() {
const transitionType = this.properties.transitionType;
switch (transitionType) {
case 'slideLeft':
return animationManager.slideIn('left', {
duration: this.properties.duration,
timingFunction: this.properties.easing
});
case 'slideRight':
return animationManager.slideIn('right', {
duration: this.properties.duration,
timingFunction: this.properties.easing
});
case 'slideUp':
return animationManager.slideIn('up', {
duration: this.properties.duration,
timingFunction: this.properties.easing
});
case 'slideDown':
return animationManager.slideIn('down', {
duration: this.properties.duration,
timingFunction: this.properties.easing
});
case 'scale':
return animationManager.scale(1, {
duration: this.properties.duration,
timingFunction: this.properties.easing
});
case 'bounce':
return animationManager.bounceIn({
duration: this.properties.duration
});
case 'fade':
default:
return animationManager.fadeIn({
duration: this.properties.duration,
timingFunction: this.properties.easing
});
}
},
// 创建退出动画
createLeaveAnimation() {
const transitionType = this.properties.transitionType;
switch (transitionType) {
case 'slideLeft':
return animationManager.slideOut('left', '100%', {
duration: this.properties.duration,
timingFunction: this.properties.easing
});
case 'slideRight':
return animationManager.slideOut('right', '100%', {
duration: this.properties.duration,
timingFunction: this.properties.easing
});
case 'slideUp':
return animationManager.slideOut('up', '100%', {
duration: this.properties.duration,
timingFunction: this.properties.easing
});
case 'slideDown':
return animationManager.slideOut('down', '100%', {
duration: this.properties.duration,
timingFunction: this.properties.easing
});
case 'scale':
return animationManager.scale(0, {
duration: this.properties.duration,
timingFunction: this.properties.easing
});
case 'bounce':
return animationManager.bounceOut({
duration: this.properties.duration
});
case 'fade':
default:
return animationManager.fadeOut({
duration: this.properties.duration,
timingFunction: this.properties.easing
});
}
},
// 创建加载动画
createLoadingAnimation() {
const loadingAnimation = animationManager.loadingSpinner({
duration: 1000
});
this.setData({
loadingAnimation: loadingAnimation.export()
});
// 循环播放加载动画
if (this.properties.showLoading) {
this.startLoadingLoop();
}
},
// 开始加载循环
startLoadingLoop() {
this.loadingTimer = setInterval(() => {
if (this.properties.showLoading) {
const loadingAnimation = animationManager.loadingSpinner({
duration: 1000
});
this.setData({
loadingAnimation: loadingAnimation.export()
});
} else {
this.stopLoadingLoop();
}
}, 1000);
},
// 停止加载循环
stopLoadingLoop() {
if (this.loadingTimer) {
clearInterval(this.loadingTimer);
this.loadingTimer = null;
}
},
// 🎯 ===== 样式管理 =====
// 更新过渡类
updateTransitionClass() {
let transitionClass = this.properties.transitionType;
if (this.properties.hardwareAccelerated) {
transitionClass += ' hardware-accelerated';
}
if (this.properties.debug) {
transitionClass += ' debug';
}
this.setData({
transitionClass: transitionClass
});
},
// 更新遮罩类
updateOverlayClass() {
this.setData({
overlayClass: this.properties.overlayType
});
},
// 🔧 ===== 工具方法 =====
// 等待动画完成
waitForAnimation() {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, this.properties.duration + 50); // 添加50ms缓冲
});
},
// 手动触发进入
triggerEnter() {
this.enter();
},
// 手动触发退出
triggerLeave() {
this.leave();
},
// 重置状态
reset() {
this.setData({
transitionState: 'idle',
animationData: null
});
},
// 获取当前状态
getState() {
return {
transitionState: this.data.transitionState,
transitionType: this.properties.transitionType,
visible: this.properties.visible
};
},
// 清理资源
cleanup() {
this.stopLoadingLoop();
if (this.animationTimer) {
clearTimeout(this.animationTimer);
this.animationTimer = null;
}
}
}
});