Files
linshen acf592ab2c refactor(template): 优化模板管理与服务注入,增强错误处理并添加故障排除清单
- 添加模板管理故障排除清单,以帮助用户解决模板管理中遇到的常见问题。
- 统一服务注入逻辑,移除不必要的props定义,增强错误处理机制。
- 优化模板管理,统一服务注入与存储键管理。
- 更新 `TemplateSelect.vue`,移除 `services` prop,改用 `inject` 注入服务。
- 整合 `useTemplateManager`,统一模板选择保存逻辑及存储键管理。
- 新增 `storage-keys.ts`,集中管理存储键常量,避免重复定义,便于维护与遍历。
- 更新相关组件以适配新的模板管理方式,确保模板选择状态正确保存和恢复。
- 修正了模板类型错误的问题,确保在管理界面切换分类后添加的模板类型与当前显示的分类一致。
- 修复了模板管理器打开位置错误的问题,确保从不同入口打开模板管理器时,定位到正确的分类。
- 优化了模板保存和导入逻辑,增加了错误处理和提示。
- 确保所有异步模板操作都使用了 `await` 关键字,避免潜在的时序问题。
- 移除了 `usePromptOptimizer` 中 `selectedOptimizationMode` 的默认值,强制传入该参数。
- 优化了 `TemplateSelect` 组件中 `optimizationMode` prop 的处理,设为 `required`。
2025-06-29 10:10:26 +08:00

7.7 KiB
Raw Permalink Blame History

布局系统核心经验

📋 概述

项目中动态Flex布局系统的核心经验总结包括布局原则、常见问题解决方案、调试方法和最佳实践。

🎯 核心布局经验:动态 Flex 布局

这是本项目最重要的经验。 摒弃固定尺寸,全面使用 Flexbox 动态空间分配。

核心原则

  • 最高指导原则:一个元素若要作为 Flex 子项(flex-1)进行伸缩,其直接父元素必须是 Flex 容器(display: flex
  • 约束链完整性:从顶层到底层的所有相关父子元素都必须遵循 Flex 规则
  • 黄金组合flex: 1 + min-h-0(或 min-w-0

实施要点

/* 父容器 */
.parent {
  display: flex;
  flex-direction: column;
  height: 100vh; /* 或其他明确高度 */
}

/* 动态子项 */
.child {
  flex: 1;
  min-height: 0; /* 关键:允许收缩 */
}

/* 滚动容器 */
.scrollable {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

调试方法

当 Flex 布局失效时,从出问题的元素开始,逐层向上检查父元素是否为 display: flex

🔧 关键Bug修复案例

1. Flex 约束链断裂修复

典型错误

<!-- ❌ 父容器不是 flex子元素 flex-1 失效 -->
<div class="h-full relative">
  <TextDiff class="flex-1 min-h-0" />
</div>

<!-- ✅ 正确:父容器必须是 flex -->
<div class="h-full flex flex-col">
  <TextDiff class="flex-1 min-h-0" />
</div>

2. TestPanel 复杂响应式布局修复2024-12-21

问题现象

TestPanel.vue 中的测试结果区域存在 flex 布局问题,内容被推向上方而非正确占用可用空间,特别是在小屏模式下使用垂直堆叠布局时。

根本原因

  1. 高度约束传递不完整flex 容器缺少 min-h-0 约束,导致子项无法正确缩小
  2. 混合布局模式处理不当:大屏使用绝对定位,小屏使用 flex 布局,但两种模式下的高度约束规则不一致
  3. 标题元素参与空间分配h3 标题未标记为 flex-none,错误地参与了 flex 空间分配

修复方案

<!-- 修复前:缺少关键的 min-h-0 约束 -->
<div class="flex flex-col transition-all duration-300 min-h-[80px]">
  <h3 class="text-lg font-semibold theme-text truncate mb-3">标题</h3>
  <OutputDisplay class="flex-1" />
</div>

<!-- 修复后:完整的 flex 约束链 -->
<div class="flex flex-col min-h-0 transition-all duration-300 min-h-[80px]">
  <h3 class="text-lg font-semibold theme-text truncate mb-3 flex-none">标题</h3>
  <OutputDisplay class="flex-1 min-h-0" />
</div>

关键修复点

  • 为每个结果容器添加 min-h-0 约束
  • 将标题标记为 flex-none,防止参与空间分配
  • 为 OutputDisplay 组件添加 min-h-0,确保高度约束正确传递到组件内部

经验总结

  • 复杂响应式布局中每种布局模式flex vs absolute都需要独立验证高度约束
  • 混合布局模式的组件特别容易出现约束传递断裂,需要逐层检查
  • 标题等固定高度元素必须明确标记为 flex-none

🎯 UI状态同步与响应式数据流最佳实践2024-12-21

典型问题

在复杂的Vue组件交互中子组件内部状态的变更未能正确反映到其他兄弟组件导致UI显示与底层数据不一致。例如用户在A组件中编辑内容后B组件如测试面板获取到的仍然是编辑前的数据。

根因分析

该问题的核心在于 单向数据流组件本地状态 之间的同步间隙。当一个子组件(如OutputDisplay)的内部状态(editingContent)发生变化时,它通过emit事件通知父组件更新顶层状态。然而,依赖同一顶层状态的其他兄弟组件(如TestPanel)接收到的props是静态的,不会自动响应由emit触发的间接状态变更,从而导致数据不同步。

解决方案:构建可靠的响应式数据流架构

核心目标:确保任何源于用户交互的状态变更,都能立即、单向地同步回单一数据源Single Source of Truth并使所有依赖该数据源的组件都能自动响应更新。

实施模式

  1. 模式一:实时状态提升 (Real-time State Hoisting)

    子组件不应持有临时的、未同步的"草稿"状态。任何可编辑的状态都应在变更的瞬间通过emit事件向上同步,而不是等待某个特定动作(如"保存"或"失焦")触发。

    // 子组件OutputDisplayCore.vue
    // 通过 watch 实时将内部编辑内容同步到父级
    watch(editingContent, (newContent) => {
      if (isEditing.value) {
        emit('update:content', newContent);
      }
    }, { immediate: false });
    
  2. 模式二:时序与竞态控制 (Timing and Race Condition Control)

    对于需要清空或重置状态的异步操作(如开始流式加载),必须确保状态变更操作(如退出编辑、清空内容)在异步任务启动前完成。nextTick 是解决此类DOM更新与状态变更竞态问题的关键。

    // 状态管理方usePromptOptimizer.ts
    async function handleOptimize() {
        isOptimizing.value = true;
        optimizedPrompt.value = ''; // 1. 同步清空状态
        await nextTick();          // 2. 等待DOM和状态更新完成
    
        // 3. 启动异步服务
        await promptService.value.optimizePromptStream(...);
    }
    
  3. 模式三:外部事件驱动的状态重置

    当一个动作(如优化)需要影响兄弟组件的状态(如强制退出编辑)时,应通过顶层组件的监听与方法调用(ref.method())来实现,而不是让组件间直接通信。

    // 父组件PromptPanel.vue
    // 监听顶层状态变化,调用子组件方法
    watch(() => props.isOptimizing, (newVal) => {
      if (newVal) {
        outputDisplayRef.value?.forceExitEditing();
      }
    });
    

核心设计原则

  • 单一数据源 (Single Source of Truth):任何共享状态都必须由唯一的、高阶的组件或状态管理器拥有。子组件只能通过props接收和通过emit请求变更。
  • 响应式数据流闭环:确保"用户输入 -> emit -> 更新顶层状态 -> props -> 更新所有相关子组件"这个数据流是完整且自动响应的。
  • 系统化调试策略当遇到状态不同步问题时从数据源头顶层状态到消费端子组件Props逐级添加临时日志是快速定位数据流"断点"的最有效方法。

快速问题排查

布局问题

  1. 检查 Flex 约束链是否完整
  2. 确认 min-h-0 是否添加
  3. 验证父容器是否为 display: flex

滚动问题

  1. 检查是否有中间层错误的 overflow 属性
  2. 确认高度约束是否从顶层正确传递
  3. 验证滚动容器是否有正确的 overflow-y: auto

状态同步问题

  1. 检查数据流是否形成闭环
  2. 确认是否存在临时状态未同步
  3. 验证组件间的依赖关系

💡 核心经验总结

  1. Flex约束链: 从顶层到底层必须保持完整的Flex约束链
  2. 最小高度约束: min-h-0 是动态布局的关键,允许元素正确收缩
  3. 混合布局验证: 不同布局模式需要独立验证约束传递
  4. 状态同步: 建立完整的响应式数据流,避免组件间状态不一致
  5. 系统化调试: 逐层检查约束链和数据流,快速定位问题根源

🔗 相关文档


文档类型: 经验总结
适用范围: Flex布局系统开发
最后更新: 2025-07-01