我用 ArkTS 自研了一个鸿蒙原生思维导图组件,已上架 ohpm,并让 DeepSeek 驱动它渲染复盘脑图

25 阅读12分钟

我用 ArkTS 自研了一个鸿蒙原生思维导图组件,已上架 ohpm,并让 DeepSeek 驱动它渲染复盘脑图

一行命令安装:

ohpm install mindmap-harmony ohpm 详情页:

ohpm.openharmony.cn/#/cn/detail… 组件源码:

github.com/725lizi/Min… 落地应用:

github.com/725lizi/Foc…

一、先看成果

这是一个 HarmonyOS NEXT 原生(ArkUI + ArkTS)思维导图 HAR 组件库,零 WebView、零三方依赖,已经通过 ohpm 中心仓审核正式上架(v1.0.0,MIT 协议,整包 59KB)。

它能做的事:

  • 传入一棵标准树节点 JSON,自动完成树形布局、节点渲染、缩放平移、节点编辑;

  • 支持 JSON 序列化 / 反序列化、组件截图、一键保存 PNG 到系统相册;

  • 内置自研的后序轮廓紧凑布局算法,不对称的树也能排得紧凑、不重叠;

  • 74 个本地单元测试守护,覆盖数据模型、布局算法、视口状态机、序列化、编辑控制、主题。

更有意思的是,我在自己的另一个应用 FocusTimer(鸿蒙专注计时 + DeepSeek AI)里真实使用了它:把用户一周的专注记录交给 DeepSeek,让大模型输出思维导图结构化 JSON,再由这个组件直接在 App 内渲染出「效率复盘脑图」;断网、没配 Key、AI 返回脏数据时,自动降级为一棵本地规则树,页面永远不白屏。

整条链路:

本地专注记录 → 组装上下文 Prompt → DeepSeek 流式输出

→ JSON 清洗/纠错/归一化 → 反序列化为 MindTree → 自研组件渲染

                  ↓ 任何一步失败

            本地规则树兜底渲染

focus-timer-ai (2).png

:本文所有图片已随稿放在

article_images

文件夹,在掘金 / 华为开发者社区编辑器里按下方「配图清单」逐张拖入对应位置即可(平台会自动托管图片,不依赖外链)。

配图清单(按文中出现顺序):

序号文件出现位置 / 说明
1focus-timer-ai.png第一节成果,AI 成功路径(紫色 ✨ AI 徽章)
2basic.png4.1/4.2 布局与整树适配,基础渲染真机图
3gesture.png4.2 手势交互,双击 / 平移 / 捏合
4edit.png4.3 键盘流编辑与选中描边
5export.png4.4 序列化往返与保存 PNG 到相册
6focus-timer-rule.png第五节,断网 / 无 Key 规则兜底路径

二、为什么要自己造这个轮子

市面上的鸿蒙脑图方案大多是两种:WebView 套一个 H5 脑图库(启动慢、包体大、手势跟手性差),或者只给一堆节点让你自己摆坐标。我想要的是:

  1. 纯原生:ArkUI 组件直接绘制,双指缩放、单指平移要跟手;

  2. 数据驱动:调用方只管给树数据,坐标全部由布局算法算,不需要手摆;

  3. 职责干净:组件库不内置任何 AI、网络依赖,其他开发者 ohpm install 之后不需要配置任何 API Key;

  4. 能被真实项目使用,而不是只跑在 Demo 里。

第 3 点是整个项目最重要的架构决策,后面会专门讲 ——AI 能力全部放在上层 App,组件只认标准 JSON。正是这条边界,让同一个组件既能被普通开发者当纯 UI 库用,也能被我自己拿来渲染大模型的输出。

三、三行代码接入

import { MindTree, MindNode, MindMapView } from 'mindmap-harmony';

const tree = new MindTree('中心主题');

tree.addChildTo(tree.root.id, new MindNode('n1', '分支一'));

// build() 中挂载;编辑后把 refreshTick 自增即可触发重新布局

MindMapView({ root: this.tree.root, refreshTick: this.tick })

组件只认这样一份标准树节点 JSON 契约(也兼容大模型 / 后端直接吐出的裸根节点):

{

  "id": "root",

  "text": "中心主题",

  "children": \[

    { "id": "n1", "text": "分支一", "children": \[] }

  ]

}

四、核心技术点拆解

4.1 自研紧凑树形布局:后序轮廓(tidier)算法

脑图布局的难点不在对称的「教科书树」,而在不对称的真实树:一个分支有 3 层、另一个分支是叶子,怎么排才能既不重叠又紧凑?

我实现的是经典 tidy tree(Reingold–Tilford 思想)的后序轮廓版本:

  • 后序遍历:先排好所有子树,再处理父节点;

  • 每个子树维护自己的左 / 右轮廓(每一层最靠外的节点坐标);

  • 相邻兄弟子树按轮廓逐层计算最小避让距离,只做一次整树平移,不反复重排;

  • 父节点居中在孩子上方,连线天然不穿透。

复杂度是 O (n・深度)。一棵典型 G4 形态的小树(根下 A、B 两支,A 有多层后代、B 是叶子),紧凑布局后整树高度从 212 收到 182,叶子 B 自动收在 A 的子树下方,没有大片空洞。

这部分是纯逻辑:输入树结构,输出每个节点的 x/y 和连线表,不 import 任何 ArkUI 能力,所以可以在 Node 里离线单测,也可以在大模型辅助生成后用黄金坐标独立验收。

4.2 视口状态机:把「缩放平移」做成纯逻辑

手势代码最容易写成一团面糊。我的做法是把视口状态(scale、offsetX、offsetY)和手势识别分开:

  • ViewportController 是一个纯状态机:zoomBy / panBy / clampScale / clampOffset / reset,缩放上下限、平移钳制(不让内容被拖出视野)全在这里,有独立单测;

  • computeFitView 是一个整树适配纯函数:输入内容宽高、视口宽高、留白,输出「让整棵树完整居中」的初始缩放比和平移量;

  • ArkUI 侧只负责把手势事件翻译成对状态机的调用,再把结果映射到 scale()/translate()。

由此得到几个体验:首次进入自动 fit-to-screen 整树居中;双击在「放大 2x / 回到适配视图」之间切换;用户一旦手动缩放 / 平移过,布局刷新就不会再抢视口。

4.3 键盘流编辑与选中态

按钮点选适合触屏,但高频录入需要键盘流(XMind/MindNode 的肌肉记忆):

  • 回车:在选中节点后加一个同级节点(选中根节点时降级为加子级);

  • Tab:下沉一层加子级,并消费掉按键事件、拦住默认焦点跳转;

  • 输入框为空时按 Delete:删除选中节点(根节点受保护),输入框有文字时不拦截,保证正常删字。

渲染层新增一个可选入参 selectedId:命中的节点用主题里预留的琥珀色(#F59E0B)画 2px 描边,其余节点维持默认灰边;不传这个参数的页面视觉零变化。选中态放在组件库内部而不是让每个页面自己画框,接入方就能免费得到一致的选中反馈。

编辑操作统一走 EditController 一个入口,渲染层只读树、不改树 —— 单一数据源让撤销 / 刷新 / 测试都简单很多。

basic.png

gesture.png

edit.png

4.4 图片导出:用新 API,不留弃用调用

组件截图走的是 UIContext.ComponentSnapshot#get 新 API(全局 componentSnapshot.get 从 API 18 起弃用),ImageExporter.saveToGallery 再通过 photoAccessHelper 保存 PNG 到系统相册,内部处理了运行时权限申请和成功 / 失败 / 拒绝授权三种状态。

一个工程细节:HAR 包本身不声明任何权限,权限由宿主 App 在自己的 module.json5 里声明 —— 组件不越权替接入方做决定。

export.png

4.5 序列化:宽容读、严格写

JsonSerializer 反序列化时兼容两种输入:完整信封 {format, version, root} 和裸根节点 {id, text, children};对非法输入抛出带错误码的异常(空输入、JSON 非法、缺字段、类型错误),而不是返回一棵半残的树让渲染层崩溃。这个「宽容读、严格写、错误可识别」的设计,恰好是后面接大模型输出的关键。

五、和 DeepSeek 闭环:组件保持纯净,容错全部在上层

这是整个项目我最喜欢的部分。FocusTimer 是一个已经接好 DeepSeek(兼容 OpenAI 协议、流式返回)的专注计时应用,我让它基于用户一周的专注数据生成复盘脑图。

5.1 为什么 AI 绝不写进组件库

如果组件库里内置 AI 调用,会立刻带来三个问题:所有安装者都要配 API Key;网络 / 模型的不确定性污染纯 UI 组件;单测要 mock 网络。所以边界划得非常硬:

  • 组件库:只接收标准 MindNode JSON,负责渲染 / 交互 / 导出,零网络、零 AI import;

  • App 业务层:负责组 Prompt、调 DeepSeek、清洗返回 JSON、失败兜底。

5.2 容错链路(重点)

大模型不可怕,可怕的是它「偶尔不听话」。真实返回里可能裹着 ```json 代码围栏、带解释性文字、id 重复或缺失、节点文本超长、children 不是数组。我在业务层做了三道工序:

  1. MindMapPromptBuilder:把专注统计(本周 / 上周时长、科目分布、打断次数等)注入 Prompt,固定输出四个分支(总体情况 / 科目分布 / 专注质量 / 下周行动),约束 8~20 个节点、深度 2~3 层、叶子文案不超过 16 个汉字,stream:true 流式返回;

  2. MindMapJsonExtractor:剥围栏、截取第一个 { 到最后一个 };归一化时根节点固定 id、缺失 / 重复 id 按层序补全、空白文本给默认值、超长文本截断、非法 children 置空,且整个过程幂等;解析失败给出明确错误码(空 / 无 JSON / 非法 JSON);

  3. RuleMindMapBuilder:只要出现「没配 Key / 断网 / 流式报错 / JSON 解析失败」中任意一种,直接用本地统计数据拼一棵四分支齐全的规则树,页面照常出图,并给用户一条橙色提示说明当前是本地结果。

DeepSeek 正常 → 紫色「✨ AI 生成」徽章 + 绿色提示

无 Key/断网/坏 JSON → 灰色「本地规则」徽章 + 橙色提示

组件的 deserialize 是最后一道闸:业务层归一化后的数据还要再过一遍组件自己的严格校验,双层保险。

focus-timer-rule.png

六、质量工程:我怎么敢说它「能用」

这个项目我刻意用了比一般课设项目严格得多的验证方式:

  • 组件库 74 个 hypium 本地单元测试:数据模型、布局、视口、序列化、编辑、主题全覆盖;

  • 黄金坐标 + 随机不变量审计:布局算法先由大模型产出,我独立手算 9~12 组黄金坐标逐位比对,再在 Node 里重写一遍函数,跑 2 万组随机树,断言「无重叠、连线不穿透、必装得下」等不变量,全部为 0 违例才冻结;

  • AI 纯函数 25 个单测 + 跨项目审计:FocusTimer 侧的 Prompt 构建 / JSON 清洗 / 规则兜底是纯函数,25 个用例离线跑;还用 2 万组随机摘要和恶意脏树文本,真实穿过组件库的反序列化器做跨项目审计,验证任何脏数据都不会让组件崩溃;

  • 三路径装机手测:在线出 AI 树、断网 / 无 Key 出规则树、返回重进无残留且原 AI 周报零回归。

一个方法论:不 import ArkUI、输入数字输出数字的纯逻辑,交给大模型写并配黄金用例;碰组件生命周期、手势、现有类签名的 UI 接线,由更懂鸿蒙的代码模型处理。两类任务分开路由,再用独立验收(而不是看模型自己说「通过了」)兜底,效率和质量都最高。

七、ohpm 上架实战:四个没人提前告诉你的坑

上架本身不要钱,但审核是真的会退包。把我踩平的四个坑列出来,帮你少走弯路:

  1. SSH 公钥必须 ≥ 4096 位。2048 位网站直接提示「公钥长度太小」,用 ssh-keygen -t rsa -b 4096 生成;

  2. 私钥必须带口令,而且只认经典 PEM 加密格式。无口令私钥直接被拒;新版 OpenSSH 格式(BEGIN OPENSSH PRIVATE KEY,即使已加密)也不认,必须加 -m PEM,生成后文件头应包含 Proc-Type: 4,ENCRYPTED。口令不能明文写进配置,要用 ohpm 的加密组件加密后存到 .ohpmrc 的 key_passphrase;私钥文件权限还要收紧到仅所有者可读;

  3. author 字段必须带邮箱和网址。只写一个名字会被 400 退回(no author url or author email),要写成 {name, email, url};

  4. 包内必须有非空 CHANGELOG.md。README、LICENSE 之外,审核还要求更新日志,放在模块根目录并确认被打进 HAR。

另外:同一版本号提交后不能重复发布,被退回改完要升版本号(如 1.0.1);「包内含源码」的警告对 MIT 开源项目是正常的,不用处理。最终我的包 59.1KB、21 个文件,提交后进入自动化扫描 + 人工审核,通过后 ohpm install mindmap-harmony 即可安装。

八、写在最后:这个项目的简历叙事

很多简历项目要么「只调了一下大模型 API」,要么「写了个组件但没人用」。这套东西把两件事缝成了闭环:

  • 会造底层可复用的轮子:自研布局算法、手势状态机、序列化、导出,74 个测试,发布到 ohpm 中心仓,任何开发者都能安装;

  • 会把轮子结合大模型做成产品:真实 App 里消费这个组件,处理流式返回、脏 JSON、离线兜底等工程问题;

  • 有明确的架构判断力:AI 在上、组件纯净,通过标准 JSON 契约解耦,两个仓库 README 互相引用、都有真机截图。

面试时可以直接演示:打开 ohpm 详情页 → 新建工程一行命令装上 → 打开 FocusTimer 现场生成一棵 AI 复盘脑图 → 断网再点一次,降级成规则树。能现场跑通的东西,比十行「精通鸿蒙开发」有说服力得多。

资源链接


本文涉及的组件版本为 mindmap-harmony 1.0.0,基于 HarmonyOS API 24 / DevEco Studio 6.1。