在这里插入图片描述

网罗开发 (小红书、快手、视频号同名)

  大家好,我是 展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等方向。在移动端开发、鸿蒙开发、物联网、嵌入式、云原生、开源等领域有深厚造诣。

图书作者:《ESP32-C3 物联网工程开发实战》
图书作者:《SwiftUI 入门,进阶与实战》
超级个体:COC上海社区主理人
特约讲师:大学讲师,谷歌亚马逊分享嘉宾
科技博主:华为HDE/HDG

我的博客内容涵盖广泛,主要分享技术教程、Bug解决方案、开发工具使用、前沿科技资讯、产品评测与使用体验。我特别关注云服务产品评测、AI 产品对比、开发板性能测试以及技术报告,同时也会提供产品优缺点分析、横向对比,并分享技术沙龙与行业大会的参会体验。我的目标是为读者提供有深度、有实用价值的技术洞察与分析。

展菲:您的前沿技术领航员
👋 大家好,我是展菲!
📱 全网搜索“展菲”,即可纵览我在各大平台的知识足迹。
每周定时推送干货满满的技术长文,从新兴框架的剖析到运维实战的复盘,助您技术进阶之路畅通无阻。


引言

很多人把 HarmonyOS 应用做到 PC 形态之后,第一反应是:

把原来的页面体系搬上来
用 router 管理跳转
用页面承载功能

也就是典型的:

“页面驱动 + 路由驱动”模型

但一旦你的应用开始变复杂,很快就会出现这些问题:

  • 页面一切换,状态丢失
  • 多窗口之间数据混乱
  • 返回逻辑越来越复杂
  • UI 和数据严重耦合
  • 越优化,越不可控

这时候你需要意识到一个关键点:

在鸿蒙 PC 上,“页面跳转”本身就是错误设计。

一、什么是“页面跳转模型”

一句话解释:

用页面切换来表达应用状态变化

典型流程是这样的:

点击按钮
↓
router.push()
↓
进入新页面
↓
页面初始化数据

看起来没问题,对吧?但问题在于:

你把“状态变化”,错误地表达成了“页面变化”。

二、PC 场景的本质:不是流程,而是“并行状态”

先对比一下:

移动端模型

页面 A
↓
跳转
↓
页面 B

核心特点:

单线程流程

鸿蒙 PC 模型

侧边栏 + 主区域 + 面板 + 多窗口

用户行为是:

同时操作多个区域
随时切换上下文
状态持续存在

也就是说:

PC 是“并行状态系统”,不是“页面流程系统”。

三、为什么“页面跳转”会出问题

因为它隐含了一个错误前提:

“同一时间只有一个活跃上下文”

但在 PC 上:

  • 编辑器在运行
  • 文件树在响应
  • 设置面板在打开
  • 另一个窗口也在活跃

这时候你如果还在用:

router.push('/editor')

实际上是在做:

强制切断当前状态,创建新上下文

结果就是:

  • 状态被重建
  • 数据被重置
  • 用户体验断裂

四、页面 ≠ 状态容器

很多代码是这样写的:

@Entry
@Component
struct EditorPage {
  @State content: string = ''
}

问题在于:

content 绑定在页面实例上

一旦:

页面销毁

结果:

数据直接消失

于是你开始:

  • 用全局变量兜底
  • 手动缓存数据
  • 写恢复逻辑

最后变成:

页面只是壳,状态到处都是。

五、本质问题:你把“UI 生命周期”当成了“状态生命周期”

页面模型的本质是:

页面创建 → 页面销毁

但状态应该是:

创建 → 持续存在 → 被更新

当你把两者绑定时:

UI 的变化,直接影响数据存在性

这在 PC 上是灾难级设计。

六、正确模型:状态驱动 UI,而不是页面驱动应用

你需要从:

Page → Page → Page

转变为:

State → UI

示例对比

页面跳转模型 错误代码

onClick() {
  router.push('/file/123')
}

状态驱动模型 正确代码

onClick() {
  fileStore.open('123')
  uiState.mainView = 'Editor'
}

变化点:

  • 不再跳转页面
  • 只更新状态
  • UI 自动变化

七、UI 不再是“页面”,而是“视图组合”

在 PC 上,你不应该设计:

有哪些页面?

而应该设计:

当前界面由哪些视图组成?

示例

uiState = {
  sidebar: 'FileTree',
  main: 'Editor',
  panel: 'Settings'
}

UI 渲染:

build() {
  Sidebar(this.uiState.sidebar)
  Main(this.uiState.main)
  Panel(this.uiState.panel)
}

切换行为:

uiState.panel = 'Search'

而不是:

router.push('/search')

八、多窗口:页面模型直接失效

一旦涉及多窗口:

WindowA → /editor
WindowB → /settings

问题马上出现:

  • Router 是全局还是局部?
  • 页面栈怎么隔离?
  • 状态如何共享?

这时候你会发现:

页面跳转根本无法描述多窗口结构。

正确方式:Workspace 模型

class Workspace {
  id: string
  uiState: UIState
  stores: StoreSet
}

每个窗口:

  • 独立 UI 状态
  • 独立数据上下文
  • 独立交互逻辑

九、“返回”在 PC 上其实是伪需求

很多人会执着于:

router.back()

但现实是:

  • PC 用户很少依赖“返回”
  • 用户依赖的是“切换上下文”

比如:

Alt + Tab
点击窗口
切换面板

所以:

“返回上一页”是移动端思维,不是 PC 需求。

十、为什么你会越写越复杂

因为页面跳转带来的问题是:

  • 状态被拆碎
  • 数据同步困难
  • 多窗口无法扩展
  • 逻辑分散不可控

但最致命的是:

你以为在管理流程,其实在破坏状态。

十一、一个完整对比

页面驱动

点击
↓
跳转页面
↓
初始化数据
↓
渲染 UI

状态驱动

点击
↓
更新状态
↓
UI 自动变化

十二、一个完整示例

状态层

class FileStore {
  currentFileId: string = ''

  open(id: string) {
    this.currentFileId = id
  }
}

UI 状态

class UIState {
  mainView: string = 'Empty'
}

行为

onOpenFile(id: string) {
  fileStore.open(id)
  uiState.mainView = 'Editor'
}

UI

build() {
  if (uiState.mainView === 'Editor') {
    return Editor(fileStore.currentFileId)
  }

  return EmptyView()
}

没有:

router.push
router.back

十三、一个快速自检清单

如果你的鸿蒙 PC 项目:

  • 大量使用 router.push
  • 页面内部保存核心状态
  • 页面销毁导致数据丢失
  • 写了复杂的“返回逻辑”

那几乎可以确定:

你在用移动端思维做 PC 应用。

总结

在鸿蒙 PC 上,“页面跳转”不是一种能力,而是一种限制。

对比:

维度 页面驱动 状态驱动
核心单位 页面 状态
数据位置 页面内部 独立 Store
UI 更新 手动/生命周期 自动响应
多窗口 很难支持 天然支持

真正应该做的是:

用状态组织系统,用 UI 表达状态。

一旦你还在依赖:

页面跳转

那本质上就是:

用旧时代的工具,解决新时代的问题。

而结果通常只有一个:

系统越做越复杂,最终不可控。

Logo

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

更多推荐