ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

【HarmonyOS 7 平行视界深度实战】02 从普通页面到第一个平行视界 Demo

【HarmonyOS 7 平行视界深度实战】02 从普通页面到第一个平行视界 Demo 文章目录前言一、配置三个文件建立最小配置链路二、Navigation 只维护一条普通路由栈三、观察系统如何跳转页面总结完整代码Index.etsmodule.json5easy_go.json前言现有 Navigation 页面已经能从首页进入详情页再进入二级详情页。应用放到 Tablet 宽窗口以后希望首页继续留在左侧详情链路显示在右侧。页面代码本身仍然保持单栏系统根据 EasyGo 的页面关系组织左右区域。这里要分清路由关系和显示位置。pushPathByName决定哪个页面进入路由栈它不会承诺页面出现在左栏、右栏或整窗。EasyGo 提供另一层信息让系统在满足设备和窗口条件时识别主页、关联页与显示模式。两层信息共同生效普通窗口仍按单页路由工作宽窗口才有机会形成平行视界。一、配置三个文件建立最小配置链路要保持原有路由不动新增变量就应先收敛到配置链路。easy_go.json放在entry/src/main/resources/base/profile/文件名可以调整但是module.json5中的资源引用必须保持一致。平行视界配置只支持放在 entry 模块配置后对应用生效。现有多模块项目常在这里踩坑。业务页面可能位于 HAR 或 HSP开发者便顺手把 EasyGo 放到页面所在模块。系统读取的是 entry 模块配置页面代码放在哪里与配置入口属于两个问题。资源名也要同时检查文件名和$profile:后面的引用改了其中一处会造成资源无法匹配。模块配置通过easyGo引用$profile:easy_go让 entry 模块找到这份 profile 资源。打包检查还要确认资源引用随 HAP 一起生效。EasyGo 使用两层结构。第一层选择设备类型第二层的displayModeOptions决定窗口显示模式。我们这个 Demo 使用common让通用配置同时覆盖支持条件内的设备{common:{displayModeOptions:{wideWindowMode:navigationSplit,squareWindowMode:navigationSplit,navigationSplitOptions:{homePage:navBar,relatedPage:DetailPage}}}}字段当前值工程含义wideWindowModenavigationSplit长方形宽窗口使用 Navigation 路由的平行视界squareWindowModenavigationSplit方形宽窗口采用相同路由方案homePagenavBarNavigation 的首页作为主页relatedPageDetailPage详情页作为静态关联页这四个字段把系统需要的最小信息分成两组窗口模式决定何时采用 Navigation 路由的平行视界主页与关联页决定初始页面关系。relatedPage依赖homePage也不支持传递动态参数。它适合分类首页、首个详情页这类稳定的页面。商品 ID、文章 ID 等业务参数继续由 Navigation 路由传递所以不能写进 EasyGo 页面关联。我们将homePage设为navBar描述的是 Navigation 首页区域将relatedPage设为DetailPage使用的是路由名称必须与pushPathByName和 Builder 判断中的名称一致。这里的名称属于字符串约定编译器很难替开发者发现拼写差异。我们的最小 Demo 只保留一个常量值便于人工核对业务工程可以集中管理路由名称减少配置与代码各写一份造成的漂移。页面关联也不承担数据加载的功能。系统识别出DetailPage后详情内容仍要根据 Navigation 参数、状态容器或业务仓库获取。如果详情页只能依靠首页对象的临时引用工作宽窗口和进程恢复场景都容易出现空白。把路由参数控制在可序列化、可校验的 ID 或查询条件范围内会让这个最小链路更容易扩展。配置已经说明系统怎样识别页面页面先后顺序和返回关系仍要回到 Navigation。二、Navigation 只维护一条普通路由栈EasyGo 已经确定页面怎样进入左右区域Navigation 还要提供唯一而稳定的页面顺序。页面创建一个NavPathStack并让 Navigation 和它一一对应pageMap再根据名称构建两个 NavDestination。一个 Navigation 对应一个NavPathStack这个约束决定了示例中的首页、详情和二级详情共享同一条返回路径。初学者有时会在每个子页面重新创建栈对象按钮仍然可以执行返回行为却落到另一条空栈上。示例使用Provide和Consume传递同一个实例目的正是让入栈、返回一级和清空回首页作用于同一份状态。Provide(pageStack)pageStack:NavPathStacknewNavPathStack()BuilderpageMap(name:string){if(nameDetailPage){DetailPage()}elseif(nameMorePage){MorePage()}}// 首页点击按钮后执行letparam:RouteParamnewRouteParam()param.title商品详情 Athis.pageStack.pushPathByName(DetailPage,param)这段代码让首页、详情页和二级详情页共享了同一个栈同时没有创建任何左右容器。首页把DetailPage放到栈顶参数对象使用显式类型避开arkts-no-untyped-obj-literals。同一条栈确认后DetailPage 才继续把 MorePage 入栈this.pageStack.pushPathByName(MorePage,param)this.pageStack.pop()this.pageStack.clear()两个子页面通过Consume使用同一个 NavPathStack因此pop()只移除当前栈顶clear()清空全部 NavDestination 节点并回到 NavBar。为了让模拟器画面只受 EasyGo 影响Navigation 继续保持普通单栏栈模式.mode(NavigationMode.Stack).title(首页).navDestination(this.pageMap)到这里路由代码只能产生单页覆盖和正常返回。满足 EasyGo 条件后若出现左右区域就可以确认分栏来自系统平行视界。页面文件中没有 Row、SideBarContainer 或 NavBar 双栏代码。实际业务还要分别处理路由返回和业务状态关闭。例如用户在 MorePage 修改了草稿pop()只改变页面栈草稿是否保留取决于状态存放位置clear()也不会自动清除全局选择或缓存。最小 Demo 用静态文字排除了这类干扰接入真实数据时应给离开页面、返回首页和重新进入分别定义预期。如果现有项目已经设置NavigationMode.Auto或NavigationMode.Split建议在复现阶段临时回到 Stack再观察 EasyGo 是否单独生效。这样做不会决定最终产品方案只是减少证据混杂。确认平行视界链路以后再恢复项目原有模式并完成组合回归。三、观察系统如何跳转页面配置链路与路由链路都已经固定了运行阶段只需要让两者在同一个宽窗口里合流。最小操作路径是首页 → DetailPage → MorePage两次跳转足以观察左栏是否保留以及右栏是否跟随栈顶变化。当前 EasyGo 没有显式设置mode。API 26 的mode默认值为1对应导航模式。导航模式为保持左侧主页路由跳转继续发生在右侧。我们的当前 Demo 只确认最小页面链路不引入选中状态等额外变量。大家观察画面时需要同时核对三项结果左栏内容来自首页右栏标题随栈顶页面变化返回按钮按 MorePage→DetailPage→首页的顺序工作。若左栏出现手写列表或两栏在窄窗口中仍强制存在当前画面可能混入应用自己的分栏实现。操作到 MorePage观察首页是否保留在左侧MorePage 是否位于右侧中间是否出现系统分隔区域并检查 NavDestination 标题栏与返回按钮。这份证据已经足够证明最小链路在当前 API 26 Tablet 模拟器中可见也给后续实验提供了对照组。修改模式、比例或页面关系以后只要最小组仍能复现就可以把新增异常收敛到本次改动。若最小组也失效应优先检查 entry 配置、资源打包和运行窗口条件。构建阶段已经确认以下结果检查项状态证据范围ArkTSCheckPASSCompileArkTS 阶段没有类型与语法诊断CompileArkTSPASSAPI 26 源码完成编译PackageHap / assembleHapPASS生成 unsigned HAPEasyGo 资源PASS打包后的 module 包含easyGo$profile:easy_goTablet 视觉PASS人工只覆盖截图中的首页 MorePage 状态真机待验证没有扩大模拟器结论这张表把证据分成编译、打包和视觉三层。编译通过说明代码能被 API 26 SDK 接受打包通过说明 EasyGo 进入产物人工截图才说明当前 Tablet 窗口出现了预期区域。三层结果合在一起最小 Demo 才能作为后续参数实验的稳定对照组。总结普通 Navigation 工程接入最小平行视界时可以保留原有首页、DetailPage、MorePage 和同一条NavPathStack。module.json5只负责找到 EasyGoeasy_go.json再声明navigationSplit、主页与关联页系统由此获得宽窗口中的页面组织规则。我目前手里还没有可以测试 HarmonyOS 7 的真机所以相关内容现阶段主要通过 HarmonyOS 7 模拟器进行验证真机上的系统表现、设备差异和实际体验后面有条件再继续补测最终还是以实际设备运行结果为准。完整代码Index.etsclassRouteParam{title:string}EntryComponentstruct Index{Provide(pageStack)pageStack:NavPathStacknewNavPathStack()BuilderpageMap(name:string){if(nameDetailPage){DetailPage()}elseif(nameMorePage){MorePage()}}build(){Navigation(this.pageStack){Column({space:20}){Text(平行视界验证).fontSize(30).fontWeight(FontWeight.Bold)Text(当前页面首页).fontSize(20).fontColor(#333333)Text(点击按钮进入详情页观察平行视界生效以后首页和详情页的位置变化。).fontSize(16).fontColor(#666666).lineHeight(24).width(100%)Button(打开详情页).width(100%).height(52).onClick((){letparam:RouteParamnewRouteParam()param.title商品详情 Athis.pageStack.pushPathByName(DetailPage,param)})Column({space:10}){Text(观察重点).fontSize(18).fontWeight(FontWeight.Medium)Text(① 首页进入详情页时是否出现左右分栏).fontSize(15).width(100%)Text(② 首页是否继续保留).fontSize(15).width(100%)Text(③ 详情页出现在哪个区域).fontSize(15).width(100%)Text(④ 二级详情继续打开时页面怎样推进).fontSize(15).width(100%)}.width(100%).padding(16).backgroundColor(#F2F3F5).borderRadius(16)}.width(100%).height(100%).padding(24).alignItems(HorizontalAlign.Start)}// 固定 Stack避免 Navigation 自己进入普通 Split 模式。.mode(NavigationMode.Stack).title(首页).navDestination(this.pageMap).width(100%).height(100%)}}Componentstruct DetailPage{Consume(pageStack)pageStack:NavPathStackbuild(){NavDestination(){Column({space:20}){Text(详情页).fontSize(30).fontWeight(FontWeight.Bold)Text(当前页面DetailPage).fontSize(20).fontColor(#333333)Text(这个页面用于观察打开第一层详情后的页面位置。).fontSize(16).fontColor(#666666).lineHeight(24).width(100%)Column({space:8}){Text(商品 A).fontSize(22).fontWeight(FontWeight.Medium)Text(价格 ¥299).fontSize(18)Text(第一层详情内容).fontSize(15).fontColor(#666666)}.width(100%).padding(20).backgroundColor(#F2F3F5).borderRadius(16)Button(继续打开二级详情).width(100%).height(52).onClick((){letparam:RouteParamnewRouteParam()param.title商品详情 Bthis.pageStack.pushPathByName(MorePage,param)})Button(返回上一层).width(100%).height(52).buttonStyle(ButtonStyleMode.TEXTUAL).onClick((){this.pageStack.pop()})}.width(100%).height(100%).padding(24).alignItems(HorizontalAlign.Start)}.title(详情页)}}Componentstruct MorePage{Consume(pageStack)pageStack:NavPathStackbuild(){NavDestination(){Column({space:20}){Text(二级详情页).fontSize(30).fontWeight(FontWeight.Bold)Text(当前页面MorePage).fontSize(20).fontColor(#333333)Text(这个页面用于观察连续打开详情时左右区域以及返回栈怎样变化。).fontSize(16).fontColor(#666666).lineHeight(24).width(100%)Column({space:8}){Text(商品 B).fontSize(22).fontWeight(FontWeight.Medium)Text(价格 ¥399).fontSize(18)Text(第二层详情内容).fontSize(15).fontColor(#666666)}.width(100%).padding(20).backgroundColor(#F2F3F5).borderRadius(16)Button(返回详情页).width(100%).height(52).onClick((){this.pageStack.pop()})Button(返回首页).width(100%).height(52).buttonStyle(ButtonStyleMode.TEXTUAL).onClick((){this.pageStack.clear()})}.width(100%).height(100%).padding(24).alignItems(HorizontalAlign.Start)}.title(二级详情页)}}module.json5{ module: { name: entry, type: entry, description: $string:module_desc, mainElement: EntryAbility, deviceTypes: [ phone, tablet, 2in1 ], deliveryWithInstall: true, installationFree: false, easyGo: $profile:easy_go, pages: $profile:main_pages, abilities: [ { name: EntryAbility, srcEntry: ./ets/entryability/EntryAbility.ets, description: $string:EntryAbility_desc, icon: $media:layered_image, label: $string:EntryAbility_label, startWindowIcon: $media:startIcon, startWindowBackground: $color:start_window_background, exported: true, skills: [ { entities: [ entity.system.home ], actions: [ ohos.want.action.home ] } ] } ], extensionAbilities: [ { name: EntryBackupAbility, srcEntry: ./ets/entrybackupability/EntryBackupAbility.ets, type: backup, exported: false, metadata: [ { name: ohos.extension.backup, resource: $profile:backup_config } ] } ] } }easy_go.json{common:{displayModeOptions:{wideWindowMode:navigationSplit,squareWindowMode:navigationSplit,navigationSplitOptions:{homePage:navBar,relatedPage:DetailPage}}}}
返回列表