HarmonyOS PC 应用,先做文档模型


子玥酱 (掘金 / 知乎 / CSDN / 简书 同名)

大家好,我是 子玥酱,一名长期深耕在一线的前端程序媛 👩‍💻。曾就职于多家知名互联网大厂,目前在某国企负责前端软件研发相关工作,主要聚焦于业务型系统的工程化建设与长期维护。

我持续输出和沉淀前端领域的实战经验,日常关注并分享的技术方向包括 前端工程化、小程序、React / RN、Flutter、跨端方案,

在复杂业务落地、组件抽象、性能优化以及多端协作方面积累了大量真实项目经验。

技术方向: 前端 / 跨端 / 小程序 / 移动端工程化 内容平台: 掘金、知乎、CSDN、简书 创作特点: 实战导向、源码拆解、少空谈多落地 **文章状态:**长期稳定更新,大量原创输出

我的内容主要围绕 前端技术实战、真实业务踩坑总结、框架与方案选型思考、行业趋势解读 展开。文章不会停留在"API 怎么用",而是更关注为什么这么设计、在什么场景下容易踩坑、真实项目中如何取舍,希望能帮你在实际工作中少走弯路。

子玥酱 · 前端成长记录官 ✨

👋 如果你正在做前端,或准备长期走前端这条路

📚 关注我,第一时间获取前端行业趋势与实践总结

🎁 可领取 11 类前端进阶学习资源 (工程化 / 框架 / 跨端 / 面试 / 架构)

💡 一起把技术学"明白",也用"到位"

持续写作,持续进阶。

愿我们都能在代码和生活里,走得更稳一点 🌱

文章目录

引言

在上一篇里我们已经达成一个共识:

在 HarmonyOS PC 场景下,

页面不再是核心,
文档才是。

但很多人在真正落地时,会立刻卡在一个现实问题上:

文档模型,

到底是一个类?

一套状态?

还是一个复杂框架?

如果你一开始就把"文档模型"想得太大,那这一步几乎一定会走偏。

常见误解:文档模型 ≠ 文件读写

很多人第一次听到"文档模型",下意识会想到:

  • 打开文件
  • 保存文件
  • 解析内容

于是代码很快就会变成这样:

ts 复制代码
class FileService {
  load(path: string): string
  save(path: string, content: string)
}

然后页面里这样用:

ts 复制代码
onPageLoad(path) {
  this.content = FileService.load(path)
}

onPageDestroy() {
  FileService.save(path, this.content)
}

表面上看,你"有文件了",但这里其实还没有文档模型

因为:

文件只是存储介质,

文档是运行时对象。

文档模型解决的不是"存不存",而是"活多久"

在 PC 应用里,真正麻烦的问题往往是这些:

  • 什么时候该保存?
  • 多个窗口是不是同一份内容?
  • 页面销毁了,状态还在不在?
  • 程序崩溃前,哪些改动是"已确认"的?

这些问题,文件 API 本身一个都解决不了

所以文档模型的第一件事,不是 IO,而是:

明确谁拥有状态,以及状态的生命周期。

最小可用的文档模型,长什么样

一个合理的起点,其实非常克制:

ts 复制代码
class Document {
  id: string
  content: string
  dirty: boolean

  applyChange(change) {
    this.content = apply(this.content, change)
    this.dirty = true
  }

  markSaved() {
    this.dirty = false
  }
}

注意这里的几个点:

  • 文档是内存对象
  • 状态集中在一个地方
  • 是否需要保存,是文档自己的判断

页面不再持有核心状态:

ts 复制代码
class EditorPage {
  doc: Document

  onLoad(docId) {
    this.doc = DocumentManager.open(docId)
  }

  onInput(change) {
    this.doc.applyChange(change)
  }
}

这一刻开始,页面只是文档的使用者

文档管理器,是比页面更重要的中枢

一旦有多个文档、多窗口,你一定会需要一个统一入口:

ts 复制代码
class DocumentManager {
  docs = new Map<string, Document>()

  open(id) {
    if (!this.docs.has(id)) {
      this.docs.set(id, loadDocument(id))
    }
    return this.docs.get(id)
  }

  close(id) {
    const doc = this.docs.get(id)
    if (doc && doc.dirty) {
      save(doc)
    }
    this.docs.delete(id)
  }
}

这一步非常关键,因为它意味着:

文档的生死,不再由页面决定。

页面只是 attach / detach:

ts 复制代码
onPageDestroy() {
  DocumentManager.detach(this.doc.id)
}

什么时候真正 close,由文档管理器统一判断。

多窗口问题,其实在这里自然消失了

一旦文档是中心,多窗口几乎不用"设计"。

ts 复制代码
const doc = DocumentManager.open(fileId)

openEditorWindow(doc)
openEditorWindow(doc)

两个窗口:

  • 看到的是同一份 content
  • 操作的是同一份状态
  • 保存策略一致

你不需要:

  • 复制状态
  • 手动同步
  • 写额外的桥接逻辑

因为模型本身已经对齐了 PC 使用方式

页面要做的事情,反而变少了

在文档模型下,页面职责会被强制压缩:

ts 复制代码
class EditorPage {
  render(doc) {
    draw(doc.content)
  }

  onUserInput(event) {
    this.doc.applyChange(parse(event))
  }
}

页面不再负责:

  • 状态持久化
  • 生命周期判断
  • 资源回收策略

这不是"页面被削弱",而是职责终于对了

为什么一定要"先"做文档模型

很多项目会想:

先把功能写出来,

后面再抽文档模型。

现实通常是:

  • 状态已经散落在页面里
  • 生命周期假设已经固化
  • 多窗口是补丁
  • 保存逻辑全是特判

这时候再引入文档模型,往往意味着一次大规模重构。

所以在 PC 场景下,正确的顺序应该是:

先定义文档如何存在,
再决定页面如何展示。

一个简单的自检点

如果你现在开始写 HarmonyOS PC 应用,可以问自己一句话:

页面关了,我的数据还应该在吗?

如果答案是"应该在",那这个数据就不该属于页面

总结

在 HarmonyOS PC 应用里,

文档模型不是高级设计,

而是基础设施

它解决的不是"写得优不优雅",而是:

  • 状态是否集中
  • 生命周期是否清晰
  • 多窗口是否天然成立
  • 长时间运行是否安全

当你一开始就把文档模型立住,后面的页面设计、窗口管理、状态同步,都会顺着来。

相关推荐
AI_零食1 天前
鸿蒙PC Electron跨平台应用开发:24时区时间表应用详解
前端·华为·electron·开源·harmonyos·鸿蒙
提子拌饭1331 天前
爆发效果技术——基于鸿蒙PC Electron框架实现
华为·架构·electron·开源·harmonyos·鸿蒙·鸿蒙系统
坚果派·白晓明1 天前
鸿蒙PC三方库使用:使用 AtomCode + Skills 自动完成鸿蒙化三方库spdlog集成
c++·华为·ai编程·harmonyos·skills·atomcode·c/c++三方库
再见6581 天前
【鸿蒙实战】从零开发「随机决策器」——选择困难症终结者
华为·harmonyos
国霄1 天前
从编译产物看懂 ArkUI V2 `@BuilderParam` 的反应式陷阱
harmonyos
再见6582 天前
鸿蒙Next实战开发(四):个人中心与系统设置页面开发
华为·harmonyos
超梦dasgg2 天前
详细讲解 AI 上下文(Context)
人工智能·状态模式
坚果派·白晓明2 天前
[鸿蒙PC三方库移植适配] 使用 AtomCode + Skills 自动完成spdlog鸿蒙化适配
c++·华为·ai编程·harmonyos·skills·atomcode
不爱学英文的码字机器2 天前
[鸿蒙PC命令行移植适配]移植rust三方库sd到鸿蒙PC的完整实践
华为·rust·harmonyos
烛衔溟2 天前
HarmonyOS 基础 UI 构建 —— 组件、布局与沉浸式效果
ui·华为·harmonyos