HarmonyOS 7 实战开发 01:搭建内容工作台基础框架
做鸿蒙开发有一阵子了,从最开始照着官方文档写 Demo,到现在独立负责一个完整项目,中间踩了不少坑。这篇开始做一个连载,把我们团队做内容工作台项目的整个过程拆成五篇,从基础框架搭起来,一步步做到可上线。
先说一下这个项目:一个内容聚合工作台,左侧导航、中间内容流、右侧详情面板,类似那种三栏布局的工具类应用。规模不算大,但五脏俱全,正好适合用来讲 HarmonyOS 7 的实际开发流程。
工程初始化与目录结构
用 DevEco Studio 创建工程的时候,选 Empty Ability,API 版本选 HarmonyOS 7(API 12)。创建完之后,不要默认的文件结构就直接写业务代码,先把目录按模块分好,不然后面越写越乱。
我们的目录结构大概是这样的:
entry/src/main/ets/
├── pages/ # 页面入口
│ └── WorkbenchPage.ets
├── components/ # 可复用组件
│ ├── NavSideBar.ets
│ ├── ContentCard.ets
│ └── DetailPanel.ets
├── model/ # 数据模型
│ └── ContentItem.ets
├── viewmodel/ # 视图模型
│ └── WorkbenchViewModel.ets
├── utils/ # 工具类
│ └── Logger.ets
└── common/ # 公共资源和常量
└── Constants.ets
这个结构看着普通,但实际项目中很重要。很多人一开始把所有东西都塞在 pages 目录里,写到后面一个文件几千行,改都不敢改。
三栏布局实现
内容工作台的核心是三栏布局:左侧导航、中间内容区、右侧详情。用 ArkUI 的 Row 布局就能实现,但要注意比例分配和边界处理。
下面是主页面的布局代码,文件位置在 pages/WorkbenchPage.ets:
@Entry
@Component
struct WorkbenchPage {
@State selectedNavId: number = 0;
@State selectedContent: ContentItem | null = null;
build() {
Row({ space: 0 }) {
// 左侧导航栏 - 固定宽度 200vp
NavSideBar({
selectedId: this.selectedNavId,
onSelect: (id: number) => {
this.selectedNavId = id;
}
})
.width(200)
.height('100%')
.backgroundColor('#f5f5f7')
// 中间内容区 - 占满剩余空间
Column() {
// 顶部搜索栏
SearchBar()
// 内容列表
ContentList({
onItemClick: (item: ContentItem) => {
this.selectedContent = item;
}
})
}
.layoutWeight(1)
.height('100%')
.backgroundColor('#ffffff')
// 右侧详情面板 - 固定宽度 360vp
DetailPanel({
content: this.selectedContent
})
.width(360)
.height('100%')
.backgroundColor('#fafafa')
}
.width('100%')
.height('100%')
}
}
这里的关键点:左侧和右侧用固定宽度,中间用 layoutWeight(1) 占满剩余空间。这样不管窗口怎么缩放,中间内容区都会自适应。

基础组件拆分
不要把所有 UI 都写在一个 build 方法里。上面代码里的 NavSideBar、ContentList、DetailPanel 都是独立组件,各自管理自己的 UI 和逻辑。
以左侧导航栏为例,文件位置在 components/NavSideBar.ets:
@Component
export struct NavSideBar {
@Prop selectedId: number;
onSelect: (id: number) => void = () => {};
private navItems: string[] = ['推荐', '前端', '后端', '设计', '产品'];
build() {
Column({ space: 4 }) {
Text('内容工作台')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 20, top: 20 })
.alignSelf(ItemAlign.Start)
.padding({ left: 16, right: 16 })
ForEach(this.navItems, (item: string, index: number) => {
Row() {
Text(item)
.fontSize(15)
.fontColor(this.selectedId === index ? '#007aff' : '#333333')
.fontWeight(this.selectedId === index ? FontWeight.Medium : FontWeight.Normal)
}
.width('100%')
.height(44)
.padding({ left: 16, right: 16 })
.backgroundColor(this.selectedId === index ? '#e8f0fe' : 'transparent')
.borderRadius(8)
.onClick(() => {
this.onSelect(index);
})
}, (item: string) => item)
}
.width('100%')
.height('100%')
.padding({ left: 8, right: 8 })
}
}
这个组件的设计思路:用 @Prop 接收当前选中项,用回调函数把点击事件传给父组件。数据和展示分离,组件本身不维护业务状态,只负责 UI 和事件转发。

工程配置注意事项
有几个配置点一开始很容易忽略:
1. 横竖屏锁定:工作台类应用一般只支持横屏,在 module.json5 里把 orientation 设成 landscape,不然竖屏下布局会乱。
2. 沉浸式状态栏:默认状态栏是白色背景,和应用内容区会有一条分割线。在 EntryAbility 里设置一下,让内容延伸到状态栏下面,视觉上更整体。
3. 字体大小适配:手机和折叠屏上字体大小差异很大,不要写死字号。用 vp 单位,或者用资源限定符做不同尺寸下的字体适配。
这些配置点看着小,但实际做项目的时候,一开始不处理,后面改起来很麻烦。
小结
这篇是整个系列的基础。工程结构搭好、三栏布局跑通、基础组件拆出来,后面加业务逻辑就顺畅了。下一篇会讲怎么用状态管理把这些组件串起来,实现交互联动。
更多推荐



所有评论(0)