# 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 路由栈,如下:

- 每个 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 样式等。 |