7.8 KiB
7.8 KiB
模态框图表抽搐问题修复
📅 修复日期
2025年10月1日
🐛 问题描述
症状
在点击EDA学术发表指南的场所卡片时,弹出的模态框中的图表会出现"抽搐"现象:
- 图表在渲染时会突然变大或变小
- 图表尺寸会快速闪烁调整
- 视觉体验不流畅
根本原因
时序问题:图表在模态框动画进行中就开始渲染,而此时容器的尺寸还在变化。
问题流程(修复前)❌
1. 点击卡片
2. 立即渲染图表(容器尺寸 = 卡片大小)
3. GSAP动画开始
4. 容器从卡片大小 → 模态框大小(0.5秒动画)
5. 图表被迫在动画中重新计算尺寸
6. 结果:图表"抽搐"
问题代码
// ❌ 错误:图表在动画之前渲染
modalContent.innerHTML = `...`;
// 渲染图表(此时容器尺寸还在变化)
const ctx = canvas.getContext('2d');
activeChart = new Chart(ctx, {...});
// GSAP动画(容器尺寸正在改变)
const tl = gsap.timeline({
onComplete: () => { isAnimating = false; }
});
tl.to(modal, {
width: targetW, // 容器宽度变化
height: targetH, // 容器高度变化
duration: 0.5
});
✅ 修复方案
核心思路
延迟图表渲染:等待模态框动画完成后再渲染图表,确保容器尺寸已经稳定。
修复后的流程 ✅
1. 点击卡片
2. 设置模态框内容(但不渲染图表)
3. GSAP动画开始
4. 容器从卡片大小 → 模态框大小(0.5秒动画)
5. 动画完成回调触发
6. 渲染图表(容器尺寸已稳定)
7. 结果:图表平滑出现,无抽搐
🔧 技术实现
1. 提取图表渲染为独立函数
之前 ❌
// 图表渲染代码直接嵌入在 openModal 中
try {
const Chart = (window as any).Chart;
const ctx = canvas.getContext('2d');
activeChart = new Chart(ctx, {...});
} catch (err) {
console.warn('绘制图表时出错:', err);
}
现在 ✅
/**
* 渲染图表(独立函数,在动画完成后调用)
*/
function renderVenueChart(venue: VenueData): void {
try {
const Chart = (window as any).Chart;
if (Chart && venue.acceptanceValue !== null) {
const canvas = document.getElementById('venueChart') as HTMLCanvasElement;
if (!canvas) return;
const ctx = canvas.getContext('2d');
if (ctx) {
// 使用 requestAnimationFrame 确保画布尺寸已稳定
requestAnimationFrame(() => {
activeChart = new Chart(ctx, {
type: 'bar',
data: {...},
options: {
responsive: true,
maintainAspectRatio: false,
...
}
});
});
}
}
} catch (err) {
console.warn('绘制图表时出错:', err);
}
}
2. 在动画完成回调中调用
之前 ❌
const tl = gsap.timeline({
onComplete: () => {
isAnimating = false;
}
});
现在 ✅
const tl = gsap.timeline({
onComplete: () => {
isAnimating = false;
// 动画完成后渲染图表
renderVenueChart(venue);
}
});
3. 添加 requestAnimationFrame 保护
requestAnimationFrame(() => {
activeChart = new Chart(ctx, {...});
});
作用:
- 确保在浏览器下一帧渲染前执行
- 给容器一个重绘的机会
- 确保尺寸计算准确
4. 简化模式同步修复
function openSimpleModal(venueId: string): void {
// ... 设置内容 ...
// 简化模式下也渲染图表
renderVenueChart(venue);
}
📊 时序对比
修复前的时序 ❌
时间轴:
0ms - 点击卡片
0ms - 渲染图表(容器 = 300x200)
10ms - GSAP动画开始
10ms - 容器尺寸变化开始
100ms - 图表检测到容器变化,重新计算
200ms - 容器继续变化
300ms - 图表再次调整(抽搐)
500ms - 动画结束
510ms - 图表最终稳定
修复后的时序 ✅
时间轴:
0ms - 点击卡片
0ms - 设置内容(图表占位符)
10ms - GSAP动画开始
10ms - 容器尺寸变化
500ms - 动画完成
500ms - onComplete 回调
510ms - renderVenueChart 调用
520ms - requestAnimationFrame
530ms - 图表渲染(容器尺寸稳定 = 800x600)
540ms - 图表平滑出现 ✅
🎯 关键优化点
1. 延迟渲染
- ✅ 等待容器尺寸稳定
- ✅ 避免动画中的重新计算
2. requestAnimationFrame
- ✅ 浏览器下一帧渲染
- ✅ 确保DOM已更新
- ✅ 尺寸计算准确
3. 独立函数
- ✅ 代码复用(GSAP模式 + 简化模式)
- ✅ 逻辑清晰
- ✅ 易于维护
4. 错误处理
- ✅ try-catch 包裹
- ✅ 优雅降级
- ✅ 控制台警告
📝 修改文件
文件: /src/pages/report/ai-eda-paper-report/eda-venues-interactive.ts
修改内容:
- 新增
renderVenueChart()函数 - 修改
openModal()- 将图表渲染移到onComplete - 修改
openSimpleModal()- 调用新的图表渲染函数
代码行数: ~35行修改
🚀 构建验证
✓ 0 errors, 0 warnings
✓ 20 pages built
✓ 图表抽搐问题已修复
🎨 用户体验提升
修复前 ❌
- 图表闪烁、跳动
- 尺寸不稳定
- 视觉体验差
- 看起来像bug
修复后 ✅
- 图表平滑出现
- 尺寸稳定
- 视觉流畅
- 专业感强
💡 技术要点
Chart.js 响应式原理
options: {
responsive: true, // 响应容器尺寸变化
maintainAspectRatio: false // 不保持宽高比,填充容器
}
问题:当容器尺寸变化时,Chart.js 会自动调整图表尺寸 解决:等待容器尺寸稳定后再渲染图表
GSAP Timeline onComplete
const tl = gsap.timeline({
onComplete: () => {
// 所有动画完成后执行
renderVenueChart(venue);
}
});
优势:
- 精确的时序控制
- 保证动画完成
- 避免中途干扰
requestAnimationFrame 的作用
requestAnimationFrame(() => {
// 浏览器下一帧执行
activeChart = new Chart(ctx, {...});
});
原理:
- 等待浏览器重绘
- 确保DOM已更新
- 尺寸计算准确
- 避免布局抖动
📚 相关知识
1. Chart.js 尺寸计算
- Chart.js 基于父容器的
clientWidth和clientHeight - 动画中这些值会不断变化
- 导致 Chart.js 多次重新计算和渲染
2. GSAP 动画时序
duration: 0.5= 500msease: 'expo.out'= 先快后慢onComplete= 动画完成回调
3. 浏览器渲染流程
JavaScript → Style → Layout → Paint → Composite
↑
requestAnimationFrame 在此执行
🎯 最佳实践
处理动画中的图表渲染
- ✅ 延迟渲染 - 等待容器尺寸稳定
- ✅ 使用回调 - onComplete、onUpdate 等
- ✅ requestAnimationFrame - 确保DOM更新
- ✅ 销毁旧图表 - 避免内存泄漏
避免的错误
- ❌ 在动画进行中渲染图表
- ❌ 不检查容器尺寸
- ❌ 不使用 requestAnimationFrame
- ❌ 忘记销毁旧图表实例
🔍 调试技巧
如何验证修复
- 打开浏览器开发者工具
- 切换到 Performance 标签
- 录制点击卡片的过程
- 查看渲染时序
- 确认图表在动画完成后才渲染
控制台日志
console.log('动画开始');
const tl = gsap.timeline({
onComplete: () => {
console.log('动画完成');
renderVenueChart(venue);
console.log('图表渲染完成');
}
});
修复完成! 🎉
现在模态框弹出时图表会平滑出现,无任何抽搐现象。
建议测试:
- 点击不同的场所卡片
- 观察图表渲染是否平滑
- 检查控制台无错误
下一步:
- 运行
npm run dev测试效果 - 或直接
npm run build && ./deploy-full.sh部署