编辑器设置最容易变成“每个开关都直接改页面字段”的地方。自动保存间隔、导出格式、放大倍率、历史上限、画布背景和洋葱皮透明度看似没有关联,实际上它们有共同要求:输入可能非法、变化后需要不同程度的刷新、是否标记项目已修改也不同。bitArt 将默认值、可选范围和应用结果拆开,让设置面板不会成为隐藏的业务中心。

设置项先有默认值和边界,界面只是一个输入端

如果输入框直接把字符串写进 autoSaveIntervalSeconds,恢复项目或手工输入时就可能出现 NaN、负数或过短周期;若导出倍率无上限,大图导出会突然占用远超预期的内存。另一个误区是“任何设置变化都完整刷新”。例如导出格式变化不影响画布,洋葱皮开关却需要重绘,历史上限变化还要裁剪 undo 与 redo 栈。

设置面板与设置服务怎样避免互相越界

设置项本身不复杂,复杂的是它们在变化后的副作用不同。先规范化输入,再明确是否刷新、是否标脏、是否重排保存,面板就不会变成不可预测的控制中心。

改变设置后不一定都要完整重绘

EditorSettingsService 把默认值和范围放在同一处:自动保存默认 300 秒,非零值限制在 60 到 86400 秒;导出倍率限制 1 到 4;历史数量限制 10 到 100;洋葱皮透明度限制 10 到 80。EditorSettingsActionService 再把一次用户动作变成 SettingsApplyResult,其中分开表示 changed、requestRefresh、markDirty 和 scheduleAutoSave。

这种结构让设置面板不需要猜测副作用。它只调用 applyAutoSaveInterval 或 applyCanvasBackgroundColor,再把返回结果交给工作流。保存调度、UI 刷新和项目脏状态因此有明确的触发条件,恢复项目时也可以复用相同的规范化逻辑。

设置规范化把默认值、关闭语义和边界范围固定在服务层。

static normalizeAutoSaveSeconds(value: number): number {
  const seconds = Math.round(Number(value));
  if (isNaN(seconds)) return EditorSettingsService.DEFAULT_AUTO_SAVE_SECONDS;
  if (seconds <= 0) return 0;
  return Math.max(EditorSettingsService.MIN_AUTO_SAVE_SECONDS,
    Math.min(EditorSettingsService.MAX_AUTO_SAVE_SECONDS, seconds));
}
static normalizeExportScale(value: number): number {
  const scale = Math.round(Number(value));
  if (isNaN(scale)) return EditorSettingsService.DEFAULT_EXPORT_SCALE;
  return Math.max(EditorSettingsService.MIN_EXPORT_SCALE,
    Math.min(EditorSettingsService.MAX_EXPORT_SCALE, scale));
}

历史上限变化要同步裁剪已有历史

设置规范化的顺序是:把输入转成数值或小写字符串,处理 NaN 和空值,再在允许范围内夹紧。0 对自动保存有特殊语义,表示关闭,所以需要在最小值判断之前分支。历史上限变化不仅更新数字,还用 EditorHistoryService.trim 截断 undoStack 和 redoStack,防止 UI 显示新上限而内存中仍保留超量快照。

static applyAutoSaveInterval(target: SettingsApplyTarget, seconds: number): SettingsApplyResult {
  const result = EditorSettingsActionService.setAutoSaveInterval(target.autoSaveIntervalSeconds, seconds);
  target.customAutoSaveMinutesText = result.minutesText;
  if (!result.changed) return EditorSettingsActionService.createApplyResult(false);
  target.autoSaveIntervalSeconds = result.value;
  return EditorSettingsActionService.createApplyResult(true, true, true, true);
}

设置变化如何通知刷新和保存

设置分成两类。导出格式、倍率、自动保存和背景色属于项目配置,应在变化时标脏;洋葱皮开关和透明度还会修改画布可见效果,需要增加 dirtyVersion 或请求刷新。历史上限本身不强制全量画布重绘,但要让历史面板读取裁剪后的数组。

设置应用结果把刷新、保存和历史裁剪分开,让每个控件只触发必要的后续动作。

static applyMaxHistoryCount(target: SettingsApplyTarget, count: number): SettingsApplyResult {
  const result = EditorSettingsActionService.setMaxHistoryCount(target.maxHistoryCount, count,
    target.undoStack, target.redoStack);
  if (!result.changed) return EditorSettingsActionService.createApplyResult(false);
  target.maxHistoryCount = result.value;
  target.undoStack = result.undoStack;
  target.redoStack = result.redoStack;
  return EditorSettingsActionService.createApplyResult(true, false, true);
}

设置面板最容易积累的隐性错误

  • 不要只在 UI 控件限制范围,项目恢复、文件导入和未来接口同样会绕过控件。
  • 自动保存的非正数统一表示关闭,NaN 才回退为默认间隔;这两条规范化路径要明确区分。
  • 历史数量减小时要同步裁剪 undo 和 redo,不能只换一个显示数字。

设置服务本质上是输入边界和副作用边界的汇合点。它不会替代持久化服务,也不会替代渲染服务;它负责把“用户想设成什么”变成“项目允许处于什么状态”,再清楚地告诉上层哪些后续动作必要。

设置项需要一张副作用清单

设置项的回归适合做成一张副作用表。每个设置写清楚四件事:允许的范围、输入非法时的回退、是否要刷新画布、是否需要保存。比如导出格式改变只需保存配置,洋葱皮开关需要刷新画布,自动保存间隔还要重排定时器,历史上限需要裁剪两个栈。用这张表检查,比凭感觉在面板上点一遍更不容易漏掉隐藏副作用。

还要验证连续设置。先把历史上限调大并画出多条历史,再调小,随后调回大值,旧快照不应凭空恢复;先关闭自动保存再改成自定义分钟数,旧定时器应被清除、新定时器按规范化秒数重建。设置系统的稳定性来自这些状态转换,而不是静态页面上显示了几个选项。

怎样确认设置范围和副作用匹配

设置检查的重点是边界值和副作用:值正确不代表刷新和保存时机正确。

  • 把自动保存输入为 0、30、300、90000 和非数字,确认得到关闭、下限、正常值、上限和默认值。
  • 将历史上限从较大值降到较小值,确认 undo 与 redo 都被裁剪且画布不回退。
  • 切换 PNG、JPG、GIF 和不同倍率,确认只更新导出配置,不无故重绘画布。
  • 开启洋葱皮并调整透明度,确认画布刷新;修改背景色后重新打开项目,确认设置可恢复。
编辑器设置检查记录
非法数值被规范化而非直接写入
自动保存 0 与非零最小值语义明确
历史上限同步裁剪两个栈
画布相关设置才触发相应刷新

设置项暂不覆盖的偏好范围

当前设置集中在编辑器功能和项目体验,不涵盖账号偏好、云同步策略或系统级主题。对单项目创作而言,先保证设置可校验、可恢复、作用范围明确,比把所有个性化选项都塞进面板更重要。

这一篇的重点是让每一项设置都有可校验的取值和明确的副作用。最后一篇把大屏上的键盘和鼠标输入接到同一套工具与面板状态中,为整个系列收束。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐