# routerx **Repository Path**: dingtalkrepo/routerx ## Basic Information - **Project Name**: routerx - **Description**: No description available - **Primary Language**: Unknown - **License**: BSD-3-Clause - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2025-01-07 - **Last Updated**: 2025-05-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 简介 本项目基于鸿蒙 NEXT 版本的一多特性,设计了一套具有一多特性的页面栈管理框架。使用本框架,你可以快速获得以下特性: 1. 具有一多特性,能适配多种尺寸的设备(包括手机、折叠屏、PAD)。 2. 可结合 Tabs 组件搭建出多 Tab 的主页框架。 3. 在宽屏设备上(比如 Pad、PC)具有四栏样式的页面栈。 4. 支持侧边栏 Overlay 和 Embed 两种模式。 5. 支持半屏 Sheet 样式的页面栈。 6. 支持全局居中样式、页面内容区居中样式的 Dialog 页面栈。 7. 支持页面 Uri 和 name 两种模式的页面路由。 ## 项目结构 本项目中主要有四个模块组成: 1. dingui:包含钉钉 style 的 Colors、一多特性的 DTPopup 组件、窗口管理(DTWindowManager)等。 2. router:核心钉钉页面栈管理以及路由框架,包括核心类:DTNavRouter、DTNavigation 等。 3. tabkit:辅助模块,封装了基础的侧边栏 TabsBar、底部 TabsBar 等,使用本模块可快速结合 Tabs 组件搭建出多 Tabs 的主页框架。 4. entry:演示了使用 dingui、router、tabkit 快速搭建具有钉钉样式的主页框架。 ## 断点定义 本框架当前定义了三个断点:sm、md、lg,框架的一多特性也是基于这三个断点适配。 | 断点名 | 定义 | |:---:|:-------------------------------| | lg | 大屏设备,宽度 > 800 vp,比如大屏pad、pc电脑等 | | md | 中屏设备,宽度在 600 - 800 vp,比如折叠屏 | | sm | 小屏设备,通常对应手机 | ## 如何使用 ### 构建 DTNavRouter 每个 UIAbility 均需要创建一个 DTNavRouter 实例,我们建议定义在 UIAbility 的 onCreate 生命周期回调里。 ```c const navRouter = new DTNavRouter.Builder() .ability(this.context) .storage(this.storage) .breakPoint((): DTBreakPoint => { return this.windowManager.getBreakPoint() }) .create() ``` ### 使用 DTNavigation 构建首页 使用 Tabs + DTNavigation + SideTabsBar 组件, 每个 Tab 页均包含一个 DTNavigation。(完整版请参考 MainPage.ets 文件)。 ```c Tabs({ controller: this.tabController, index: (this.tabsVM.selectedTab as BaseTabModel)?.tabIndex ?? 0 }) { ForEach(this.tabsVM.getAllTabs(), (item: BaseTabModel) => { if ((item as BaseTabModel).tabIndex >= 0) { TabContent() { DTNavigation({ tabsVM: this.tabsVM as ObservedTabsViewModel, tabModel: item, }) } .tabIndex((item as BaseTabModel).tabIndex) } }) } ``` ### 关联 DTNavRouter 和 Tabs 的 ViewModel ObservedTabsViewModel 用于定义所有 Tabs 的数据模型,同时它也是 DTNavRouter 与 Tabs 的桥梁,具体请参考 Demo 代码实现。当 DTNavRouter 绑定了ObservedTabsViewModel 对象后,如果切换了 Tab,将会自动通知 DTNavRouter 切换页面栈。 ```c tabsVM: ObservedTabsViewModel = new DemoTabsVM() this.navRouter?.bindTabsViewModel(this.tabsVM) ``` ### 创建路由页面 请使用 DTNavDestination 作为根节点,DTNavDestination 提供了丰富的配置,可用于自定义 TitleBar 等。同时按照鸿蒙官方要求,定义 Builder 以及 routerMap。 ```c @Builder export function ChatPageBuilder() { ChatPage() } @Component export struct ChatPage { @Builder page() { Text('Hello') } build() { DTNavDestination({ title: '聊天窗口', page: () => { this.page() }, menus: [ { icon: $r('app.media.setting'), onClick: () => {} } ] }) } } ``` ### 使用 DTNavRouter 路由 如下常规的路由页面,默认在当前页面栈打开对应页面 ```c DTNavRouter.from(this)?.route({ name: 'chat'}) ``` 同样也可以使用一多方式自定义页面路由栈,如下示例代码: ```c // 一多特性打开页面 DTNavRouter.from(this)?.route({ name: 'chat', container: { md: DTNavContainer.main, lg: DTNavContainer.side } }) ``` ‒ 小屏设备(sm, 手机):未指定 container,默认在当前页面栈打开 ‒ 中屏设备(md, 折叠屏):将会在主栈中打开页面 ‒ 大屏设备(lg,PAD):将会在侧边栏中打开页面 ## 方案设计 ### 框架核心类 | 类名 | 功能描述 | |-----------------------|-------------------------------------------------------------| | DTNavRouter | 路由框架总入口类 | | DTNavigation | 基于多 Navigation 实现的具有钉钉四栏特性的路由组件,每个 Tab 通常会创建一个 DTNavigation | | DTNavDestination | 页面根组件,封装了 NavDestination,里面封装了 Titlebar、页面参数等基础能力 | | DTNavController | 基于 Navigation 的页面栈管理,统一有内部类 NavRouterImpl 关联 | | PopupNavController | 继承自 DTNavController,Sheet / Dialog 类型的页面栈控制器 | | SideNavController | 继承自 DTNavController,侧边栏 Navigation 的页面栈控制器 | | DTNavTitleBar | 页面标题栏组件,封装了返回按钮、Title、右侧 Action 等能力 | | ObservedTabsViewModel | 多 Tab 场景的 View 模型,可以和 DTNavRouter 绑定,实现响应式的控制 Tab 页面栈切换。 | ### 架构设计 本项目采用多 Navigation 架构,每个 Tab 均会包含多个 Navigation 路由栈,如下: ![img.png](images/Struct.jpg) - 每个 Tab 均会包含一个 DTNavigation。 - 每个 DTNavigation 里面会包含多个 Navigation 用于做不同场景的页面栈路由,包括主页面栈、侧边栏页面栈(宽屏场景)、Popup 类的 Sheet 和 Dialog 页面栈。 - 每个 Navigation 的页面栈均有一个 DTNavController (Sheet 和 Dialog 除外)控制。 ### 页面栈的选择 当 Push 新页面时,由于框架是基于多 Navigation 实现,框架将基于以下规则查找路由栈: 1. 查找 Tab 栈:如果未指定 Tab 时,将在当前 Tab 栈,否则查找并切换到指定命名的 Tab 栈。 2. 查找页面栈控制器(DTNavController): a. 优先根据指定的 Container 查找控制器。 b. 如果未指定 Container,则根据路由时所在的 Component 所在的 Navigation,并在此 Navigation 中路由。 ### Sheet 与 Dialog 由于鸿蒙官方提供的 Dialog 组件能力的不足,钉钉自建了 DTPopup 组件,框架也基于该组件实现了半屏容器以及 Dialog 样式的页面路由栈。如下图,演示两种样式的页面路由效果: 使用示例代码: ```c DTNavRouter.from(this)?.route({ name: 'chat_setting', container: DTNavContainer.dialog, popupInfo: { position: DTPopupPosition.Root } }) ``` 其中关联的接口核心参数: | 参数名 | 参数说明 | |-----------|--------------------------------------------------------------------------------------------------------------------------------------------| | popupInfo | DTNavPopupInfo,Popup 样式 | | position | DTNavPopupInfo 中成员入参,类型 DTPopupPosition。主要支持 Root、RoutePage 两种。
- Root:在页面的根布局区域中打开,即会遮罩整个窗口
- RoutePage:在关联的 NavigationContent 区域打开 | | options | DTNavPopupInfo 中成员入参,类型 DTPopupOptions。可用于重定义更详细的 Popup 样式,包括是否是模态、页面 Height、Width、Border 样式等。 |