《新闻资讯》一、应用分层模块化整体实现指南

HarmonyOS NEXT 新闻资讯应用分层模块化开发全指南:状态管理V2 + 分层架构实战

环境 :DevEco Studio 6.1 | HarmonyOS SDK 6.1.0(23) | ArkTS

技术亮点 :状态管理V2全家桶 · HdsTabs沉浸光感悬浮页签 + Navigation路由 · 分层模块化架构

适用人群:HarmonyOS中高级开发者,希望掌握最新API和架构最佳实践


效果

---

一、项目概述

1.1 项目背景

本案例参考华为官方新闻资讯应用架构设计指南,采用分层模块化 架构,结合HarmonyOS 6.1最新的状态管理V2装饰器,从零构建一个功能完整的新闻资讯应用。

1.2 功能模块

模块 功能点 模块类型
新闻 新闻列表、新闻详情、新闻分类、下拉刷新 HAR
视频 视频列表(Grid)、视频播放 HAR
直播 直播列表(关注/直播/热门三Tab) HAR
我的 用户登录、评论管理、收藏、退出 HAR
服务 党媒云、社区融等服务 HAR

1.3 技术选型

技术点 选型 说明
状态管理 V2(@ComponentV2) 替代V1的@Component,更精准的响应式更新
底部导航 HdsTabs + BottomTabBarStyle @kit.UIDesignKit 悬浮页签,沉浸光感效果
页面路由 Navigation + NavPathStack 替代旧版router,支持声明式路由
数据懒加载 LazyForEach + IDataSource 性能优化的列表渲染方案
数据模型 @ObservedV2 + @Trace 细粒度属性级观测

二、分层模块化架构设计

2.1 三层架构

复制代码
┌─────────────────────────────────────────────┐
│         产品定制层 (Product)             	   │
│    phone (HAP Entry)						  │
│    页面框架 · 导航 · 启动页 · 路由配置          │
├─────────────────────────────────────────────┤
│         基础特性层 (Features)                 │
│    news · video · live · personal · service │
│    各模块独立HAR,仅依赖common                 │
├─────────────────────────────────────────────┤
│         公共能力层 (Common)                   │
│    common (HAR)                             │
│    数据模型 · 工具类 · 常量 · 通用组件          │
└─────────────────────────────────────────────┘

2.2 模块依赖关系图

复制代码
product/phone (HAP)
  ├── common (HAR)
  ├── features/news (HAR) ──→ common
  ├── features/video (HAR) ──→ common
  ├── features/live (HAR) ──→ common
  ├── features/personal (HAR) ──→ common
  └── features/service (HAR) ──→ common

核心原则

  • features层各模块互不依赖,只依赖common
  • phone模块聚合所有features,是唯一入口
  • common模块无外部依赖,是最底层基础设施

2.3 oh-package.json5 依赖配置

product/phone/oh-package.json5

json 复制代码
{
  "dependencies": {
    "common": "file:../../common",
    "news": "file:../../features/news",
    "video": "file:../../features/video",
    "live": "file:../../features/live",
    "personal": "file:../../features/personal",
    "service": "file:../../features/service"
  }
}

features/*/oh-package.json5(每个feature模块相同):

json 复制代码
{
  "dependencies": {
    "common": "file:../../common"
  }
}

三、状态管理V2全面应用

3.1 V1 → V2 装饰器映射表

本项目全面使用状态管理V2,以下是V1到V2的完整映射:

V1装饰器 V2装饰器 用途
@Component @ComponentV2 组件声明
@State @Local 组件本地状态
@Prop @Param 父→子单向传递
@Link @Param + @Event 父子双向绑定
@Provide @Provider 跨层级状态提供
@Consume @Consumer 跨层级状态消费
@Watch @Monitor 属性变化监听
@Observed @ObservedV2 + @Trace 类属性细粒度观测
计算getter @Computed 计算属性
aboutToAppear aboutToAppear 生命周期(不变)

3.2 数据模型设计(@ObservedV2 + @Trace)

typescript 复制代码
// common/src/main/ets/model/NewsItem.ets
@ObservedV2
export class NewsItem {
  @Trace newsId: string = '';
  @Trace newsTitle: string = '';
  @Trace newsContent: string = '';
  @Trace newsTime: string = '';
  @Trace newsImage: string = '';
  @Trace category: string = '头条';
  @Trace isGood: boolean = false;
  @Trace isCollect: boolean = false;

  constructor(id: string, title: string, content: string,
    time: string, image: string, category: string = '头条') {
    this.newsId = id;
    this.newsTitle = title;
    this.newsContent = content;
    this.newsTime = time;
    this.newsImage = image;
    this.category = category;
  }
}

关键点@Trace标记的每个属性都是独立的观测单元,修改isGood不会触发仅读取newsTitle的组件重渲染。

3.3 组件间数据流

复制代码
MainPage (@Provider 'pageStack')
  └── Navigation(pageStack)
        ├── HdsTabs (悬浮页签内容)
        │     ├── NewsHome    ── pushPathByName()
        │     ├── VideoHome   ── pushPathByName()
        │     ├── LiveHome
        │     └── PersonalHome ── pushPathByName()
        │
        └── navDestination(pageMap)
              ├── NewsDetail   ── @Consumer('pageStack') → pop()
              ├── VideoPlayer  ── @Consumer('pageStack') → pop()
              ├── LoginPage    ── @Consumer('pageStack') → pop()
              └── MyComments   ── @Consumer('pageStack') → pop()

四、HdsTabs 沉浸光感悬浮页签

4.1 HdsTabs 组件用法

项目使用 HdsTabs(@kit.UIDesignKit)实现底部悬浮导航,配合全局类 BottomTabBarStyleSymbolGlyphModifier 实现带图标的悬浮页签,通过 .labelStyle() 确保图标与文本颜色一致。

typescript 复制代码
import { HdsTabs } from '@kit.UIDesignKit';
import { SymbolGlyphModifier } from '@kit.ArkUI';
// BottomTabBarStyle 是全局类,不需要导入

@Entry
@ComponentV2
struct MainPage {
  @Local currentTabIndex: number = 0;
  @Provider('pageStack') pageStack: NavPathStack = new NavPathStack();

  private buildTabIcon(symbol: Resource, selected: boolean): SymbolGlyphModifier {
    return new SymbolGlyphModifier(symbol)
      .fontColor([selected ? $r('app.color.focus_color') : $r('app.color.placeholder_color')]);
  }

  private buildTabBar(symbol: Resource, label: string): BottomTabBarStyle {
    return new BottomTabBarStyle({
      normal: this.buildTabIcon(symbol, false),
      selected: this.buildTabIcon(symbol, true)
    }, label).labelStyle({
      unselectedColor: $r('app.color.placeholder_color'),
      selectedColor: $r('app.color.focus_color')
    });
  }

  build() {
    Navigation(this.pageStack) {
      Column() {
        HdsTabs({ index: this.currentTabIndex }) {
          TabContent() { NewsHome() }.tabBar(this.buildTabBar($r('sys.symbol.house'), '首页'))
          TabContent() { VideoHome() }.tabBar(this.buildTabBar($r('sys.symbol.video'), '视频'))
          TabContent() { LiveHome() }.tabBar(this.buildTabBar($r('sys.symbol.video_badge_adiowaves'), '直播'))
          TabContent() { PersonalHome() }.tabBar(this.buildTabBar($r('sys.symbol.person'), '我的'))
        }
        .barOverlap(true)
        .barPosition(BarPosition.End)
        .vertical(false)
        .barFloatingStyle({ barBottomMargin: 16 })
        .onChange((index: number) => {
          this.currentTabIndex = index;
        })
        .layoutWeight(1)
      }
    }
    .hideTitleBar(true)
    .navDestination(this.pageMap)
    .mode(NavigationMode.Stack)
  }
}

4.2 关键配置说明

配置 说明
HdsTabs @kit.UIDesignKit 导入
SymbolGlyphModifier @kit.ArkUI 导入,用于渲染系统图标
BottomTabBarStyle 全局类,不需要导入
buildTabIcon 构建带颜色的 SymbolGlyphModifier 图标
buildTabBar 封装图标 + 文本 + .labelStyle() 颜色配置
.barOverlap(true) 页签栏悬浮覆盖在内容之上
.barFloatingStyle() 设置悬浮样式(底部间距等)
.labelStyle() 设置文本选中/未选中颜色,与图标颜色保持一致

5.1 路由架构

本项目使用单Navigation容器 + 统一navDestination映射的路由方案:

typescript 复制代码
// 在MainPage中注册路由映射
@Builder
pageMap(name: string, param: Object) {
  if (name === 'NewsDetail') {
    NewsDetail()
  } else if (name === 'NewsCategory') {
    NewsCategory()
  } else if (name === 'VideoPlayer') {
    VideoPlayer()
  } else if (name === 'LoginPage') {
    LoginPage()
  } else if (name === 'MyComments') {
    MyComments()
  }
}

5.2 页面跳转方式

typescript 复制代码
// 列表页 → 详情页(传递数据)
this.pageStack.pushPathByName('NewsDetail', newsItem);

// 详情页 → 返回
this.pageStack.pop();

5.3 启动页特殊处理

启动页(Index.ets)作为@Entry页面,通过loadContent('pages/Index')加载,其跳转使用传统router:

typescript 复制代码
aboutToAppear() {
  setTimeout(() => {
    this.getUIContext().getRouter().replaceUrl({ url: 'pages/MainPage' });
  }, 1500);
}

这是因为pages/Indexpages/MainPage是同级的Entry页面,不在Navigation容器内。


六、模块间交互方式

6.1 导航交互

场景 方式 代码示例
Tab切换 Tabs.onChange this.currentTabIndex = index
列表→详情 pushPathByName pageStack.pushPathByName('NewsDetail', item)
详情→返回 pop pageStack.pop()
启动页→主页 router.replaceUrl getRouter().replaceUrl({url:'pages/MainPage'})

6.2 数据交互

数据流 V2机制 示例
父→子单向 @Param NewsListItem({ item: newsItem })
子→父回调 @Event onCountChange: (v) => { this.count = v }
跨层级共享 @Provider/@Consumer pageStack 在MainPage提供,各子组件消费
全局状态 AppStorage userAccountnewsData评论列表

七、项目构建步骤

7.1 环境准备

  1. 安装 DevEco Studio 6.1
  2. 配置 HarmonyOS SDK 6.1.0(23)
  3. 创建空项目,SDK选择 6.1.0(23)

7.2 模块创建

build-profile.json5 中注册所有模块:

json 复制代码
{
  "modules": [
    { "name": "phone", "srcPath": "./product/phone", "targets": [{ "name": "default", "applyToProducts": ["default"] }] },
    { "name": "common", "srcPath": "./common" },
    { "name": "news", "srcPath": "./features/news" },
    { "name": "video", "srcPath": "./features/video" },
    { "name": "live", "srcPath": "./features/live" },
    { "name": "personal", "srcPath": "./features/personal" },
    { "name": "service", "srcPath": "./features/service" }
  ]
}

7.3 路由注册

更新 product/phone/src/main/resources/base/profile/main_pages.json

json 复制代码
{
  "src": [
    "pages/Index",
    "pages/MainPage"
  ]
}

7.4 编译运行

bash 复制代码
# DevEco Studio 中点击 Run 按钮
# 或使用命令行
hvigorw assembleHap

八、注意事项与最佳实践

8.1 @ComponentV2 注意事项

  1. 不支持 @Reusable :V2组件不能使用组件复用,用 @ObservedV2 + @Trace 的细粒度更新替代
  2. @Param 必须初始化@Param 装饰的变量必须有默认值或标记 @Require
  3. @Event 替代 callback :V2中使用 @Event 而非普通函数属性进行子→父通信

8.2 Tabs 底部导航注意事项

  1. 嵌套冲突:避免在 Tabs 内容中再次使用 Tabs 组件,会导致布局冲突
  2. LiveHome 解决方案:内部 Tab 栏改用自定义 Row + Text,避免嵌套
  3. 升级路径:待 SDK 支持后可升级为 HdsTabs 实现沉浸光感效果
  1. Provider必须在Consumer的祖先组件中
  2. key匹配@Provider('pageStack')@Consumer('pageStack') 的key必须一致
  3. NavDestination页面 :通过 navDestination 注册的页面也能通过 @Consumer 获取 Provider 的值

九、总结

本项目完整演示了如何在HarmonyOS 6.1环境下,使用最新的状态管理V2分层模块化架构构建一个新闻资讯应用。核心收获:

  1. 架构清晰:三层架构(产品层/特性层/公共层)各司其职
  2. 技术前沿:全面使用V2装饰器,代码更简洁、更新更精准
  3. 稳定可靠:标准Tabs组件兼容性好,避免嵌套冲突
  4. 路由规范:Navigation + NavPathStack + @Provider + @Param 显式传参
相关推荐
木咺吟1 小时前
鸿蒙原生应用实战(一):项目搭建与首页开发 — 游戏收藏夹
华为·harmonyos
风华圆舞2 小时前
鸿蒙 + Flutter 如何把 AI 助手嵌进应用页面里——以食界探味为
人工智能·flutter·harmonyos
星栈独行2 小时前
写 Makepad Demo 不难,难的是把它写成项目
前端·程序人生·ui·rust
金启攻2 小时前
【鸿蒙原生应用实战】第五篇:活动记录页——数据筛选、统计与成就系统
harmonyos
金启攻2 小时前
【鸿蒙原生应用实战】第一篇:项目搭建与首页开发——从零构建户外助手App
华为·harmonyos
Swift社区2 小时前
AI + 鸿蒙游戏:下一代游戏架构正在形成吗?
人工智能·游戏·harmonyos
风满城332 小时前
【鸿蒙原生应用开发实战】第二篇:首页开发——宠物卡片+快捷入口+动态信息流
华为·harmonyos
枫叶丹42 小时前
【HarmonyOS 6.0】MDM Kit 深度解析:企业级 user_grant 权限集中管理策略
开发语言·华为·harmonyos
风华圆舞2 小时前
鸿蒙 + Flutter 下如何管理 AI 会话——AgentService 设计解析
人工智能·flutter·harmonyos