欢迎加入鸿蒙PC开发者社区,共同打造开发者工具生态:[鸿蒙PC开发者社区]:https://harmonypc.csdn.net/

第一部分:鸿蒙版本 Electron 框架环境搭建

环境准备:

  • 操作系统:macOS 26+
  • IDE:DevEco Studio 5.0+
  • Node.js:v18.x 或更高版本(建议 v20.18.1)
  • 硬件:≥8GB 内存(推荐 16GB)、≥20GB 可用存储空间
  • 目标设备:HarmonyOS(API 20+)PC 设备

这篇文章记录一次在 Mac 上搭建鸿蒙版 Electron 开发环境的过程。这里说的“鸿蒙版 Electron”,不是在 macOS 上直接跑普通 Electron 桌面应用,而是使用 Electron for HarmonyOS 预编译包v34.6.0-20251105.1-release 这类工程,把前端 html页面、Electron 风格的主进程和 preload 桥接逻辑,放进 HarmonyOS/OpenHarmony 应用工程里运行。

第一步 找到仓库

访问 Electron 鸿蒙仓库:华为云官方开源electron开源仓库,下载最新 Release 包(如 v34.6.0-20251105.1-release.zip)。

在这里插入图片描述

第二步 下载到本地并且将解压

在这里插入图片描述

此时你看到的libelectron这个文件夹就是解压缩之后得到的预编译的官方开源的项目了。

第三步 预览libelectron内部目录结构

在这里插入图片描述

可以看到跟根目录中有两个文件夹,lib.unstripped文件夹里面存放的是两个so库资源。

在这里插入图片描述

两一个文件夹ohos_hap下面则是我们熟悉的鸿蒙项目的正常的目录结构了。
在这里插入图片描述

ohos_hap在DevEco Studio中打开。注意,不是打开 libelectron 根目录,而是打开 ohos_hap。因为 ohos_hap 才是 DevEco Studio 能识别的 HarmonyOS/OpenHarmony 工程目录。

打开后,DevEco Studio 会自动同步工程。第一次打开可能会下载或索引一些依赖,等待同步完成即可。

工程里主要有两个模块:

模块 作用
electron HAP 入口模块
web_engine Web/Electron 运行时和桥接层

build-profile.json5 里可以看到当前工程的 SDK 配置和签名配置,例如:

{
  "compatibleSdkVersion": "5.0.5(17)",
  "runtimeOS": "HarmonyOS",
  "targetSdkVersion": "5.0.5(17)"
}

在这里插入图片描述

第四步 预览最终显示的文件

注意:electron鸿蒙版本实际上还是将web页面塞到鸿蒙原生应用的形式。所以最终运行的是静态文件夹下的前端页面。
在这里插入图片描述

第五步 确认签名配置

鸿蒙应用运行到真机或模拟器时,需要签名配置。这个项目的 ohos_hap/build-profile.json5 中已经有 signingConfigs

{
  "name": "default",
  "type": "HarmonyOS",
  "material": {
    "certpath": "/Users/luqingjiedemac/.ohos/config/default_ohos_hap_xxx.cer",
    "keyAlias": "debugKey",
    "profile": "/Users/luqingjiedemac/.ohos/config/default_ohos_hap_xxx.p7b",
    "storeFile": "/Users/luqingjiedemac/.ohos/config/default_ohos_hap_xxx.p12"
  }
}

这里文章里不要直接暴露自己的完整证书文件名和密码。写博客时可以像上面这样用 xxx 隐去敏感部分。

如果你本地没有这些签名文件,可以在 DevEco Studio 里重新生成调试签名。一般路径是:

File -> Project Structure -> Signing Configs

或者在运行配置中根据 DevEco Studio 的提示自动生成 Debug 签名。

常见签名问题包括:

  1. profile 文件不存在
  2. certpath 文件不存在
  3. storeFile 文件不存在
  4. bundleName 和 profile 不匹配
  5. 使用了别人的本地绝对路径

如果项目是从别人电脑拷贝过来的,最容易遇到第 5 个问题。解决方式是不要硬改证书密码,而是在 DevEco Studio 里重新生成自己的 Debug 签名配置。

在这里插入图片描述

第六步 连接设备或启动模拟器

项目要真正证明跑通,最好运行到鸿蒙设备或模拟器上。

如果使用真机,需要打开开发者模式和 USB 调试。连接后用 hdc 查看设备:

/Applications/DevEco-Studio.app/Contents/sdk/default/openharmony/toolchains/hdc list targets

如果能看到设备编号,说明设备连接成功。

如果使用模拟器,可以在 DevEco Studio 的 Device Manager 中创建或启动模拟器。模拟器启动后,同样可以用 hdc list targets 确认。

第七步 将华为云开源的项目运行起来

在这里插入图片描述

第二部分:实现 XH 笔记应用

第二部分不再停留在“能不能启动工程”,而是直接做一个小应用:XH 笔记

这个案例的目标不是做一个功能复杂的商业笔记软件,而是用一个足够完整的小应用,验证鸿蒙版本 Electron 框架在真实业务场景里的开发方式。页面层使用 Vue3,运行时保留 Electron 风格的 preload 和 IPC 桥接,最终由鸿蒙工程负责打包和运行。

此案例开源地址 :https://AtomGit.com/lqjmac/XHbj/tree/main

最终 XH 笔记包含这些能力:

功能 说明
笔记列表 左侧展示所有笔记,支持置顶和更新时间排序
搜索笔记 根据标题和正文筛选笔记
新建笔记 点击按钮创建一条新笔记
编辑笔记 支持标题和正文编辑
自动保存 输入后自动写入本地存储
删除笔记 删除当前选中的笔记
复制正文 调用桥接能力写入剪贴板
导出 Markdown 通过保存对话框导出 .md 文件
系统通知 复制或导出成功后发送通知
鸿蒙环境运行 在鸿蒙设备或模拟器中验证运行效果

在这里插入图片描述

一、为什么选择做 XH 笔记

环境搭建文章通常只能证明“工程能打开、命令能跑”。但真正做应用时,还会遇到状态管理、页面结构、文件能力、剪贴板、通知、开发模式和生产构建之间的差异。

XH 笔记刚好适合作为第一个实战案例。

它的业务足够简单,不会被复杂需求带偏;同时它又不是纯展示页,必须处理真实交互:

  1. 用户输入标题和正文
  2. 应用需要保存数据
  3. 列表需要跟随更新时间刷新
  4. 搜索需要即时过滤
  5. 复制和导出需要调用运行时能力
  6. 最终还要跑到鸿蒙环境里验证

这几个点串起来,就能完整验证 Vue3 页面、桥接层和鸿蒙应用容器之间的协作关系。

二、整体实现思路

XH 笔记采用左右分栏布局。

左侧是笔记列表区域,包含搜索框、新建按钮、笔记数量和笔记条目。每条笔记展示标题、正文摘要、更新时间,如果被置顶还会显示置顶标识。

右侧是编辑区域,包含标题输入框、正文输入框、置顶按钮和底部状态栏。底部状态栏显示字符数量、段落数量、更新时间和自动保存状态。

顶部是工具栏,提供:

  1. 新建笔记
  2. 复制正文
  3. 导出 Markdown
  4. 删除笔记
  5. 当前运行环境提示
  6. 自动保存时间提示

这样设计的原因是:笔记应用的高频操作都在一个页面内完成,不需要跳转多个页面,也更适合桌面和平板类窗口。
在这里插入图片描述

三、页面文件和模块拆分

这次主要改动 Vue3 业务层和运行时桥接层。

Vue3 侧新增和修改的文件如下:

src/views/Home.vue
src/components/NoteSidebar.vue
src/components/NoteEditor.vue
src/components/NoteToolbar.vue
src/composables/useNotes.ts
src/composables/useNativeBridge.ts
src/composables/useOhos.ts
src/styles/global.css
src/App.vue
src/router/index.ts

运行时桥接层新增了写文件能力:

main.js
preload.js

几个核心文件的职责如下:

文件 职责
Home.vue XH 笔记主页面,组合侧栏、编辑器、工具栏
NoteSidebar.vue 搜索框和笔记列表
NoteEditor.vue 标题、正文和编辑状态
NoteToolbar.vue 新建、复制、导出、删除等操作
useNotes.ts 笔记数据、搜索、选择、增删改、自动保存
useNativeBridge.ts 复制、导出、通知等原生能力封装
useOhos.ts window.ohos 的基础封装
main.js IPC 处理器,负责保存文件、通知、剪贴板等
preload.js 安全暴露桥接 API 给 Vue3 页面

这个拆分方式的重点是:页面组件不直接操作底层原生 API,也不直接到处读写 localStorage。业务状态集中在 useNotes.ts,原生能力集中在 useNativeBridge.ts

在这里插入图片描述

四、设计笔记数据结构

一条笔记的数据结构并不复杂:

export interface NoteItem {
  id: string
  title: string
  content: string
  createdAt: number
  updatedAt: number
  pinned?: boolean
}

字段含义如下:

字段 说明
id 笔记唯一标识
title 笔记标题
content 笔记正文
createdAt 创建时间
updatedAt 最近更新时间
pinned 是否置顶

这里没有一开始就接数据库,也没有直接把所有笔记做成文件。第一版先用 localStorage 做本地持久化,是为了尽快把业务闭环跑通。

这样做有两个好处。

第一,开发阶段可以在浏览器里快速预览,不依赖鸿蒙设备和文件系统。

第二,等页面交互稳定之后,再通过“导出 Markdown”接入文件能力,这样更容易定位问题。如果一开始就把编辑、保存、文件读写、设备权限全部混在一起,排查成本会高很多。

五、实现笔记状态管理

笔记状态集中放在:

src/composables/useNotes.ts

这个文件负责:

  1. 初始化默认笔记
  2. localStorage 恢复历史笔记
  3. 新建笔记
  4. 选择笔记
  5. 更新标题和正文
  6. 删除笔记
  7. 置顶笔记
  8. 搜索过滤
  9. 自动保存

初始化时,应用会先尝试读取本地缓存:

const STORAGE_KEY = 'xh-notes:v1'

const readNotes = (): NoteItem[] => {
  const raw = window.localStorage.getItem(STORAGE_KEY)
  if (!raw) {
    return seedNotes
  }

  const parsed = JSON.parse(raw)
  if (!Array.isArray(parsed)) {
    return seedNotes
  }

  return parsed
}

实际代码里还做了字段校验,避免本地缓存格式异常时页面直接崩掉。

笔记列表排序也放在状态层处理:

const sortNotes = (items: NoteItem[]) => {
  return [...items].sort((a, b) => {
    if (a.pinned !== b.pinned) {
      return a.pinned ? -1 : 1
    }

    return b.updatedAt - a.updatedAt
  })
}

这样组件层拿到的列表已经是排好序的,组件只负责渲染,不关心排序规则。

在这里插入图片描述

六、实现自动保存

自动保存是这个案例里很关键的一步。它让 XH 笔记从“表单演示”变成了一个真正可以持续使用的小应用。

实现思路是:标题或正文变化时,更新当前笔记的 updatedAt,然后延迟写入 localStorage

核心逻辑如下:

let saveTimer: number | undefined

const persistNow = () => {
  window.localStorage.setItem(STORAGE_KEY, JSON.stringify(notes.value))
  isSaving.value = false
  lastSavedAt.value = Date.now()
}

const scheduleSave = () => {
  isSaving.value = true
  window.clearTimeout(saveTimer)
  saveTimer = window.setTimeout(persistNow, 300)
}

这里没有每输入一个字符就立即保存,而是做了 300ms 的延迟。用户连续输入时,保存动作会被合并,体验上仍然是自动保存,但减少了频繁写入。

页面上会显示保存状态:

正在保存
已保存 22:15:08

这个状态在顶部工具栏和编辑器底部都会出现。这样用户能明确知道内容已经落盘,不需要再找“保存按钮”。

在这里插入图片描述

七、实现左侧笔记列表

左侧列表组件是:

src/components/NoteSidebar.vue

它接收三个核心参数:

defineProps<{
  notes: NoteItem[]
  currentNoteId: string
  searchTerm: string
}>()

它向外抛出三个事件:

defineEmits<{
  select: [id: string]
  create: []
  'update:searchTerm': [value: string]
}>()

这样侧栏组件本身不保存业务状态。搜索词、当前选中笔记、新建动作都交给父组件和 useNotes.ts 处理。

笔记摘要也在组件里做了简单处理:

const getExcerpt = (note: NoteItem) => {
  return note.content.trim().replace(/\s+/g, ' ').slice(0, 56) || '暂无正文'
}

展示时,一条笔记会包含:

  1. 标题
  2. 是否置顶
  3. 正文摘要
  4. 更新时间

搜索时,状态层会同时匹配标题和正文:

return sortedNotes.value.filter((note) => {
  return (
    note.title.toLowerCase().includes(keyword) ||
    note.content.toLowerCase().includes(keyword)
  )
})

在这里插入图片描述

八、实现右侧编辑器

右侧编辑器组件是:

src/components/NoteEditor.vue

它负责标题输入、正文输入、置顶按钮和底部统计信息。

标题输入:

<input
  class="title-input"
  :value="note.title"
  placeholder="笔记标题"
  @input="$emit('updateTitle', ($event.target as HTMLInputElement).value)"
/>

正文输入:

<textarea
  class="content-input"
  :value="note.content"
  placeholder="开始记录..."
  spellcheck="false"
  @input="$emit('updateContent', ($event.target as HTMLTextAreaElement).value)"
></textarea>

编辑器不直接修改笔记对象,而是通过事件把输入内容交给外层页面,再由 useNotes.ts 执行更新。这种写法比在组件里直接改对象更清晰,后续要加撤销、历史记录或云同步时也更好处理。

底部统计信息包含:

  1. 字符数量
  2. 段落数量
  3. 更新时间
  4. 保存状态

统计逻辑:

const contentStats = computed(() => {
  const text = props.note.content.trim()
  const chars = props.note.content.length
  const paragraphs = text ? text.split(/\n\s*\n/).length : 0
  return `${chars} 字符 / ${paragraphs}`
})

在这里插入图片描述

九、实现顶部工具栏

顶部工具栏组件是:

src/components/NoteToolbar.vue

它负责展示当前运行环境和常用操作按钮。

工具栏上有一个运行环境提示:

鸿蒙运行时
浏览器预览

这个状态来自桥接层:

const isNativeRuntime = computed(() => isOhosEnv)

如果当前页面运行在普通浏览器中,就显示“浏览器预览”;如果运行在鸿蒙版本 Electron 环境中,并且 window.ohos.isOhos 为真,就显示“鸿蒙运行时”。

按钮包括:

  1. 新建
  2. 复制正文
  3. 导出 Markdown
  4. 删除

当没有选中笔记时,复制、导出和删除按钮会禁用,避免空状态下误操作。

在这里插入图片描述
在这里插入图片描述

十、封装原生桥接能力

XH 笔记没有在页面里直接访问 window.ohos,而是新增了一层封装:

src/composables/useNativeBridge.ts

它对外暴露:

const {
  isNativeRuntime,
  copyText,
  exportMarkdown,
  notify,
  setWindowTitle,
} = useNativeBridge()

页面层只关心“复制正文”“导出 Markdown”“通知用户”,不需要知道底层是通过浏览器 API 还是通过鸿蒙版本 Electron 的桥接 API 完成。

复制正文:

const copyText = async (text: string) => {
  if (!text.trim()) {
    return false
  }

  return await clipboard.write(text)
}

导出 Markdown:

const exportMarkdown = async (title: string, content: string) => {
  const fileName = `${safeFileName(title)}.md`

  if (!isOhosEnv) {
    downloadInBrowser(fileName, content)
    return { ok: true }
  }

  const filePath = await saveFile({
    title: '导出 Markdown',
    defaultPath: fileName,
    filters: [{ name: 'Markdown', extensions: ['md'] }],
  })

  if (!filePath) {
    return { ok: false, canceled: true }
  }

  const ok = await writeTextFile(filePath, content)
  return { ok, filePath }
}

这里做了一个重要的降级:如果当前是普通浏览器预览,就使用浏览器下载能力导出 Markdown;如果当前是鸿蒙运行时,就调用保存对话框和写文件能力。

这样开发体验会好很多。写 UI 时可以先在浏览器里快速调试,等逻辑稳定后再跑到鸿蒙环境验证原生能力。
在这里插入图片描述

十一、给运行时补充写文件能力

原有桥接层已经有保存文件对话框,但导出 Markdown 不只是拿到路径,还需要把内容写进去。所以这次在运行时层补了一条 IPC。

main.js 中新增:

const fs = require('fs')

ipcMain.handle('ohos:writeTextFile', async (event, { filePath, content }) => {
  if (!filePath) {
    return false
  }

  await fs.promises.writeFile(filePath, content, 'utf8')
  return true
})

preload.js 中暴露:

file: {
  showSaveDialog: (options = {}) => ipcRenderer.invoke('ohos:showSaveDialog', options),
  writeTextFile: (filePath, content) =>
    ipcRenderer.invoke('ohos:writeTextFile', { filePath, content }),
}

然后在 useOhos.ts 里增加 TypeScript 封装:

const writeTextFile = async (filePath: string, content: string): Promise<boolean> => {
  if (!ohos) return false
  try {
    return await ohos.file.writeTextFile(filePath, content)
  } catch (e) {
    console.error('写入文件失败:', e)
    return false
  }
}

这样 Vue3 页面调用 exportMarkdown 时,最终会走到运行时的 ohos:writeTextFile,完成真正的文件写入。

十二、主页面如何串起所有能力

主页面文件是:

src/views/Home.vue

它把状态管理、桥接能力和 UI 组件组合起来。

页面顶部引入:

import NoteEditor from '@/components/NoteEditor.vue'
import NoteSidebar from '@/components/NoteSidebar.vue'
import NoteToolbar from '@/components/NoteToolbar.vue'
import { useNativeBridge } from '@/composables/useNativeBridge'
import { useNotes } from '@/composables/useNotes'

笔记状态来自 useNotes

const {
  filteredNotes,
  currentNote,
  currentNoteId,
  searchTerm,
  isSaving,
  lastSavedLabel,
  createNote,
  selectNote,
  updateNote,
  deleteNote,
  togglePinned,
} = useNotes()

原生能力来自 useNativeBridge

const { copyText, exportMarkdown, notify, isNativeRuntime } = useNativeBridge()

复制当前笔记:

const handleCopyNote = async () => {
  if (!currentNote.value) {
    return
  }

  const ok = await copyText(currentNote.value.content)
  if (ok) {
    showFeedback('正文已复制')
    await notify('XH 笔记', '正文已复制到剪贴板')
  } else {
    showFeedback('复制失败,请检查权限')
  }
}

导出当前笔记:

const handleExportNote = async () => {
  if (!currentNote.value) {
    return
  }

  const result = await exportMarkdown(currentNote.value.title, formatMarkdown())
  if (result.ok) {
    showFeedback(result.filePath ? `已导出 ${result.filePath}` : 'Markdown 已导出')
    await notify('XH 笔记', 'Markdown 导出成功')
  } else if (!result.canceled) {
    showFeedback('导出失败,请稍后重试')
  }
}

这里还有一个小细节:导出前会把标题和正文拼成 Markdown:

const formatMarkdown = () => {
  const title = currentNote.value.title.trim() || '未命名笔记'
  return `# ${title}\n\n${currentNote.value.content.trim()}\n`
}

这样用户导出的文件不是简单纯文本,而是可以直接被 Markdown 编辑器识别的文档。

十三、运行开发服务

开发阶段先启动 Vue3/Vite 服务:

cd ohos_hap/web_engine/src/main/resources/resfile/resources/app/vue-app
npm run dev

正常情况下会看到:

VITE v5.4.21  ready in xxx ms

Local: http://127.0.0.1:5173/

我本地启动后访问:

http://127.0.0.1:5173/

可以正常打开 XH 笔记页面。

如果端口被占用,因为当前 Vite 配置使用了 strictPort: true,服务不会自动切换到其他端口,而是直接报错。这样做的好处是鸿蒙运行时加载地址更稳定,不会出现 Vite 跑到 5174 但应用仍然访问 5173 的情况。

在这里插入图片描述
在这里插入图片描述

十四、构建前端产物

开发服务验证后,再构建生产产物:

npm run build

本次构建通过,输出类似:

vite v5.4.21 building for production...
✓ 47 modules transformed.
../dist/index.html
../dist/assets/index-xxxx.css
../dist/assets/Home-xxxx.css
../dist/assets/index-xxxx.js
../dist/assets/Home-xxxx.js
../dist/assets/vue-xxxx.js
✓ built in xxxms

这里的输出目录是:

ohos_hap/web_engine/src/main/resources/resfile/resources/app/dist

也就是说,Vue3 应用构建完成后,会被放到运行时能够加载的位置。开发模式下可以加载 Vite 服务,生产模式下则加载打包后的 dist/index.html

在这里插入图片描述

十五、在 DevEco Studio 中运行

前端构建完成后,打开 DevEco Studio。

注意这里要打开鸿蒙工程目录,而不是外层目录。打开后确认模块和运行配置正常,然后选择设备或模拟器运行。

开发模式下,可以保持 Vite 服务运行,让应用加载:

http://localhost:5173

这样修改 Vue3 页面后可以快速看到变化。

生产模式下,则先执行:

npm run build

再通过 DevEco Studio 构建和运行 HAP,让应用加载打包后的静态资源。

运行成功后,设备或模拟器中应该能看到 XH 笔记界面,包括左侧笔记列表、右侧编辑区和顶部工具栏。

在这里插入图片描述

十六、验证复制和导出能力

XH 笔记的实战价值不只在页面编辑,还在于它调用了运行时能力。

复制正文

点击“复制正文”后,页面会调用:

await copyText(currentNote.value.content)

在浏览器预览时,它会走 navigator.clipboard.writeText;在鸿蒙版本 Electron 运行时,它会走桥接层的剪贴板能力。

成功后会出现:

正文已复制

并尝试发送系统通知:

XH 笔记:正文已复制到剪贴板

在这里插入图片描述

导出 Markdown

点击“导出 Markdown”后,会把当前笔记转换成:

# 笔记标题

笔记正文

然后调用保存对话框,让用户选择保存位置。确认后由运行时写入文件。

在这里插入图片描述

十七、开发中需要注意的几个点

1. 不要让页面直接依赖原生对象

如果 Vue 组件里到处写:

window.ohos.file.showSaveDialog()

后面会很难维护。浏览器预览、鸿蒙运行时、异常降级都要在各个组件里重复判断。

这次把原生能力集中封装在 useNativeBridge.ts,页面只调用业务语义明确的方法:

copyText()
exportMarkdown()
notify()

这样组件更干净,也方便后续替换底层实现。

2. 自动保存不要写得太急

笔记应用里,用户输入非常频繁。如果每次 input 都立即写入存储,虽然第一版也能跑,但不是一个好的习惯。

这次使用 300ms 延迟保存,既保留自动保存体验,又避免频繁写入。

3. 浏览器预览和鸿蒙运行时要同时考虑

这个案例保留了浏览器降级逻辑:

  1. 剪贴板可以走浏览器 Clipboard API
  2. 导出 Markdown 可以走浏览器下载
  3. 通知可以走浏览器 Notification API

这样做的好处是前端页面开发不必每次都启动设备。等交互稳定后,再进入 DevEco Studio 和鸿蒙运行环境验证桥接能力。

4. 导出文件要分成两步

保存 Markdown 不是一个动作,而是两个动作:

  1. 通过保存对话框拿到用户选择的路径
  2. 将 Markdown 内容写入这个路径

所以桥接层需要同时具备:

showSaveDialog
writeTextFile

只有保存对话框是不够的。

5. 运行环境状态要显示出来

工具栏里显示“浏览器预览”或“鸿蒙运行时”,看起来只是一个小状态,但它在调试时很有用。

当复制、导出、通知表现和预期不一致时,先看当前运行环境,就能快速判断是浏览器降级逻辑的问题,还是鸿蒙桥接层的问题。

十八、可以继续扩展的方向

XH 笔记目前已经完成了一个基础闭环。后面可以继续扩展:

方向 说明
Markdown 预览 增加编辑/预览双栏
标签系统 给笔记添加标签并按标签筛选
文件导入 .md 文件导入笔记
文件夹分类 按工作、学习、生活分类
快捷键 支持新建、搜索、导出等快捷键
数据加密 本地保存前加密正文
云同步 接入账号体系和远端同步
原生菜单 增加更像桌面应用的菜单操作

如果继续往下做,我会优先加 Markdown 预览和文件导入。因为这两个能力能继续验证 Web 页面和原生文件能力之间的配合。

十九、总结

通过 XH 笔记这个案例,可以看到鸿蒙版本 Electron 框架不只是能展示一个 Vue 页面,它可以承载一个有真实交互的小应用。

这次实战主要验证了几件事:

  1. Vue3 可以负责主要页面和业务状态
  2. localStorage 可以先承担轻量本地持久化
  3. preload 和 IPC 可以把剪贴板、通知、文件能力暴露给前端
  4. 浏览器预览和鸿蒙运行时可以共用一套业务页面
  5. 前端构建产物可以被鸿蒙应用容器加载
  6. 应用最终可以运行到鸿蒙设备或模拟器中

这篇文章的重点不是“笔记应用本身有多复杂”,而是把一个小应用从界面、状态、自动保存、原生能力到鸿蒙运行验证完整串起来。对于熟悉 Vue3 和 Electron 开发方式的人来说,这种开发模型比较自然;对于鸿蒙应用开发来说,它也提供了一条复用 Web 技术栈的路径。

Logo

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

更多推荐