邮件、资讯、购物、IM 这一类的应用,手机上是列表点进详情,到了平板和折叠屏展开态还这么用,右边空着一大块,体验立刻显得敷衍。改吧,又是大工程:列表页要加选中态、详情要做成右栏、窗口宽度要监听、折叠切换要处理状态保持——一个"左右分栏"四个字,够写一整个迭代。

HarmonyOS 7 里有另一条路:平行视界 EasyGo。它不让你写分栏代码,而是在模块里放一份 JSON 声明"哪个页面当左栏、哪个页面当右栏",系统在窗口层把分栏做掉。应用代码一行不改,邮件应用在平板上打开就是左列表右正文,折叠屏展开自动跟着分,合上又自动回到单栏。

一、EasyGo 在哪一层做事

先把概念放准。EasyGo 是窗口级的兼容方案:系统读到你声明的配置后,把应用的窗口切成左右两个容器,左容器渲染你指定的首页,右容器渲染配对页。你的页面代码对此毫无感知——它还是那个普通的 @Entry 页面,用 router.pushUrl 正常跳转,系统决定这个跳转落在左栏还是右栏。

这套机制天生适合"列表→详情"的浅路由结构:邮箱、新闻、电商、文档库。深导航、复杂状态机的应用,EasyGo 的两栏模型兜不住,那是 Navigation 组件分栏(应用层自己做)的领地。

和 Navigation 分栏的边界后面选型一节细说,先记住一句话:EasyGo 零代码但能力受配置约束,Navigation 全可控但要重写页面结构。

二、三步接入:两份文件,零业务代码

完整的接入就三步。第一步,写配置文件 entry/src/main/resources/base/profile/easy_go.json:

{
  "common": {
    "displayModeOptions": {
      "wideWindowMode": "routerSplit",
      "routerSplitOptions": {
        "homePage": "pages/erqi/easygo/MailListPage",
        "relatedPage": "pages/erqi/easygo/MailDetailPage",
        "fullScreenPages": ["pages/erqi/easygo/MailSettingPage"],
        "transPages": ["pages/erqi/easygo/MailComposePage"],
        "mode": 1,
        "wideSplit": { "ratio": "1 | 2" }
      }
    }
  }
}

第二步,在 module.json5 的 module 对象里加一行,指向这份配置:

"easyGo": "$profile:easy_go"

注意这是 module 级属性,和 "pages": "$profile:main_pages" 平级。网上有资料写成 metadata 数组挂 ohos.easygo.window,至少在 API 26 的模块校验 schema 里不是这个形态——以本地 SDK 的 modulecheck schema 为准,就是 easyGo 字符串属性。

第三步,没有了。页面代码就是你平时写的 router 页面:列表页 router.pushUrl 到详情页,详情页 router.getParams() 拿参数,和手机上没有任何区别。

我在平板上装起来第一眼的效果:应用启动直接就是分栏,左栏收件箱占三分之一,右栏预载了详情页的空态(“未选择邮件"提示);点左栏任意一封邮件,右栏立刻换成那封邮件的正文。整个过程列表页代码里没有一行"选中”"右栏"相关的逻辑——选中态的高亮是列表页本来就有的,右栏换内容是系统做的。
1.png
1.png

三、配置结构:设备分节与窗型分派

easy_go.json 的结构是两层。顶层按设备类型分节:common(全设备默认)、phone、2in1、tablet,具体节里的配置覆盖 common——想给平板 1:2、给 2in1 电脑 1:1,就分节写。

第二层是 displayModeOptions,按窗口形态分派,这是理解 EasyGo 的关键:

键管什么取值
wideWindowMode矩形横屏窗口(平板横持、2in1)routerSplit / navigationSplit / original
squareWindowMode方形窗口(三折叠 M 态、双折叠屏展开态)routerSplit / navigationSplit / original

original 是"不动,保持手机样式"。选了 routerSplit 就必须给 routerSplitOptions,选 navigationSplit 就必须给 navigationSplitOptions,两栏都 original 则其它键都不许出现——这份 schema 的约束写得非常严,字段名拼错、结构不符,构建期直接报错,不会静默失效。

方形窗口要单独配,这是最容易踩的第一个坑。 我实测时先只配了 wideWindowMode,在折叠屏展开态(2210×2416 的近方窗口)打开应用——不分栏,列表横贯全屏。方形窗口归 squareWindowMode 管,没配就当没这回事。补上 "squareWindowMode": "routerSplit" 之后,展开态立刻分栏。如果你只在大屏平板上测过就收工,折叠屏用户拿到的是没分栏的版本,而且没有任何报错提示你去查。
21.png

21.png

窄窗口不用配:手机竖屏、折叠屏合拢的外屏,EasyGo 自动按 original 处理,我在手机竖屏上实测列表就是正常单栏,无需任何声明。

四、routerSplitOptions:每个字段干什么

这是配置的主体,逐字段过一遍(以下行为全部实测验证):

homePage / relatedPage:分栏态的左栏页与右栏页,值是 router 页面路径。启动时系统左栏加载 homePage、右栏预载 relatedPage——注意是预载,右栏一开始就是活的页面(我这里是详情页的空态),不是一张静态占位图。

transPages:只在右栏显示的过渡页。我把写邮件页放进去,实测点「写信」后左栏列表纹丝不动,写信页整个出现在右栏。适合"从详情再进一步"的轻操作页:回邮件、加备注、改标签。

fullScreenPages:不参与分栏的整屏页。设置页放进去后,点「设置」整个窗口被设置页铺满,分隔线消失。实测有个好细节:从分栏态进设置页再返回,系统恢复的是之前的分栏快照——左栏还是列表,右栏还停留在你进设置前看的那封邮件。整屏页是压栈的,不打散分栏状态。

pagePairs:细粒度的页面配对(from→to),适合左右栏关系不是"一个列表对一个详情"的多入口场景,比如从搜索页进详情、从收藏页进详情,各自配对。

mode:0 购物模式 / 1 导航模式,默认 1。官方 schema 对这两个模式只有一句枚举说明。我在 home+related 的基础结构下把 0 和 1 都跑了一遍:启动分栏、左点右出、返回行为完全一致,差异没有在这个简单结构里显现。这个值更适合 pagePairs 多配对的复杂场景,基础接入按默认 1 即可,不必纠结。

enableInSplitScreen:应用本身处于系统分屏(两应用并排)时还做不做应用内分栏,默认 false。想想也是对的:分屏里窗口已经不大,再左右分栏每栏就剩一条了。

五、分栏比例:ratio 的格式坑与拖拽

比例配置在 wideSplit / squareSplit 里,两种窗型各配各的——这也是实测里很讨喜的设计:平板宽屏 1:2、折叠屏方窗 2:3,互不干扰。

ratio 的格式是 "1 | 2":数字、空格、竖线、空格、数字。 schema 里的正则是 ^[1-9]\d* \| [1-9]\d*$,空格是格式的一部分,写 "1|2" 或 "1 : 2" 都过不了校验。实测配置 "1 | 2" 在 2880 宽的平板上,分隔线精确落在 960px;换成 "2 | 1" 重装,左栏立刻翻转为三分之二。

isDraggable 与 ratio 互斥。想让用户拖动分隔线,就把 ratio 去掉只写 "isDraggable": true——同时写两个会被 schema 的条件约束拒绝。开启后默认 1:1,用户可以在 1:2、1:1、2:1 三档之间拖动。

拖拽还有一个排查比例问题时值得知道的行为:用户拖过分隔线后,系统会记住这次拖动。我实测把 isDraggable 版本换成固定 ratio 的版本重新安装,分隔线停在 1:1 中位而不是新配置的 1:2,重启应用无效,最后卸载重装才回到配置值。也就是说调试比例配置时,如果之前拖过线,看到的位置可能不是配置值——先卸载重装排除残留状态,再判断配置是否生效。

实测拖拽还有个自动化测试层面的细节:注入的拖动动作要够慢才被识别为拖 divider。900 毫秒的快速滑动毫无反应,2000 毫秒的慢拖精确生效,分隔线从 1:1 的中点一路拖到 1:2 的位置,两侧内容跟着重排。手工拖没这个问题——这提醒的是写 UI 自动化的人,不是写应用的人。

splitDividerColor 给分隔线配色,light/dark 各一个,8 位十六进制(#RRGGBBAA)。我配了红色做验证,截图逐像素看,分隔线位置确实是红色系像素——配置真实生效,不是摆设。
31.png

32.png

41.png
42.png

六、折叠屏实测:展开分栏、合拢单栏、切换实时

折叠屏是 EasyGo 的主场,把 Mate X71 的三个状态全测了:

状态窗口实测行为
合拢(外屏)1080×2444 窄窗自动单栏,无需配置
展开(大方窗)2210×2416squareWindowMode 接管,按 squareSplit 2:3 分栏
合拢↔展开切换—实时跟随:展开瞬间分栏回来,比例保持 2:3

第三行值得强调:窗口形态变化时系统自己重排,应用收不到也不需要处理任何"折叠事件"。这就是声明式的红利——形态逻辑全部在系统侧,你声明的是意图(“这种窗型下我要分栏”),执行细节不用管。
5.gif

七、返回行为的两个细节

分栏态下的路由返回有两个实测发现,接交互预期时要心里有数。

其一,fullScreenPage 的返回是干净的:整屏页弹出,分栏快照原样恢复(前面说过)。其二,右栏内容页里调 router.back(),右栏会被清空——不是回到预载占位,是整个右栏内容消失,只剩左栏列表待在原地,再点任何一封邮件右栏才回来。也就是说"回到列表"这个按钮在分栏态下的观感是"关掉右栏",而不是"回到初始分栏"。行为本身自洽,但如果你预期 back 后右栏还挂着占位页,实际不是——要么接受,要么把详情页里的返回按钮在分栏态下做别的处理(比如换一封默认邮件)。

八、选型:EasyGo、手写一多、Navigation 分栏

三条路放在一起,按投入和产出选:

方案投入能力边界适合
EasyGo一份 JSON两栏结构、配置项内的定制存量应用、列表-详情浅路由
手写一多(断点/栅格)重写布局任意自定义对大屏有定制设计的应用
Navigation 分栏引入 Navigation 体系多栏、自定义转场新项目、复杂导航

我的建议按场景分:应用已经是稳定的 router 结构、想低成本把大屏体验从"能用"提到"体面",EasyGo 是性价比最高的一步,一个下午能上线;新起的应用直接上 Navigation,应用层分栏的自由度值得;对大屏有强定制设计(沉浸式画廊、双栏编辑器)的,老老实实手写一多。三者不互斥——EasyGo 兜底 + 个别页面 fullScreenPages 摘出来自定义,是常见的混合用法。

九、接入清单

把全部实测结论收成一张上手清单:

  1. 配置文件放 resources/base/profile/easy_go.json,module.json5 的 module 里加 "easyGo": "$profile:easy_go"(与 pages 平级,不是 metadata)。
  2. 顶层按设备分节(common/phone/2in1/tablet),具体覆盖通用。
  3. 折叠屏展开态记得配 squareWindowMode,只配 wideWindowMode 方窗不分栏。
  4. ratio 格式 "1 | 2"(空格是格式的一部分);要可拖拽就去掉 ratio 只写 isDraggable,二者互斥。
  5. 宽窗方窗比例各自独立:wideSplit 管横屏、squareSplit 管方窗。
  6. 设置页这类无关页面进 fullScreenPages,写邮件这类轻操作页进 transPages。
  7. schema 严格校验(additionalProperties: false),字段拼错构建期报错——报错是好事,对着 schema 改就行。
  8. 右栏 back 会清空右栏,交互预期按"关掉右栏"理解。
  9. 窄窗口(手机/折叠合拢)自动单栏,无需配置。
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐