《新闻资讯》七、服务模块实现指南
2026/6/12 3:00:53 网站建设 项目流程

HarmonyOS NEXT 新闻资讯应用 · 服务模块 features/service 实现指南

开发环境:DevEco Studio 6.1.0 Release
SDK版本:HarmonyOS SDK 6.1.0(23) / API 23
开发语言:ArkTS
状态管理:V2(@ComponentV2系列装饰器)
前置阅读:common模块指南 · 整体架构指南

本篇详细讲解服务模块features/service的实现。这是应用中结构最精简的 feature 模块——仅有 1 个组件ServiceHome、1 个源文件、74 行源码。虽然代码量少,但完整展示了shadow 卡片阴影Tabs + ForEach 动态生成模板字符串动态描述等实用技巧。


效果


一、模块定位与架构角色

服务模块在三层架构中处于基础特性层(features),编译为 HAR 包:

产品定制层 product/phone (HAP) ↓ 依赖 基础特性层 features/news | features/video | features/live | features/personal | features/service ← 本模块 (HAR) ↓ 依赖 公共能力层 common (HAR)

模块职责:提供各类服务入口(党媒云、社区融、法律服务、健康服务),仅包含 1 个组件:

组件文件行数类型功能
ServiceHomecomponents/ServiceHome.ets74@ComponentV2服务主页,4 分类 Tab + shadow 卡片列表

特点:与 live 模块类似,服务模块没有 NavDestination 子页面,不需要@Consumer('pageStack')。但服务模块比 live 模块更精简——没有 @Builder 列表模板,仅一个ServiceCard@Builder。


二、模块配置详解

2.1 oh-package.json5

{ "name": "service", "version": "1.0.0", "description": "Please describe the basic information.", "main": "Index.ets", "author": "", "license": "Apache-2.0", "dependencies": { "common": "file:../../common" } }

2.2 Index.ets 入口文件

export{ServiceHome}from'./src/main/ets/components/ServiceHome';

仅 2 行,导出唯一组件。外部通过import { ServiceHome } from 'service'使用。


三、完整文件结构树

features/service/ ├── oh-package.json5 (12行) 模块配置 ├── Index.ets (2行) 统一导出 ├── src/main/ │ ├── ets/ │ │ └── components/ │ │ └── ServiceHome.ets (74行) 服务主页,Tabs+shadow卡片 │ └── resources/ (图片等静态资源)

与 live 模块结构一致,没有pages/目录。


四、ServiceHome 服务主页

4.1 完整源码

import{StyleConstants}from'common';/** * 服务主页组件 * 使用 @ComponentV2 实现 * 展示党媒云服务内容 */@ComponentV2exportstruct ServiceHome{@LocalcurrentIndex:number=0;privateserviceItems:string[]=['党媒云','社区融','法律服务','健康服务'];@BuilderServiceCard(title:string,description:string){Column(){Text(title).fontSize(16).fontWeight(FontWeight.Bold).fontColor(StyleConstants.TEXT_PRIMARY)Text(description).fontSize(13).fontColor(StyleConstants.TEXT_SECONDARY).margin({top:8}).maxLines(2).textOverflow({overflow:TextOverflow.Ellipsis})}.width('100%').padding(16).backgroundColor(Color.White).borderRadius(8).shadow({radius:2,color:'#0D000000',offsetY:1})}build(){Column(){// 顶部标题Text('服务').fontSize(20).fontWeight(FontWeight.Bold).fontColor(StyleConstants.TEXT_PRIMARY).margin({left:16,top:12,bottom:8}).width('100%')// 分类TabTabs({barPosition:BarPosition.Start,index:this.currentIndex}){ForEach(this.serviceItems,(item:string,index?:number)=>{TabContent(){Scroll(){Column({space:12}){this.ServiceCard(`${item}平台`,`提供优质的${item}内容和服务,涵盖最新资讯、深度报道、专家解读等。`)this.ServiceCard(`${item}矩阵`,`整合多渠道资源,构建全方位的${item}传播体系。`)this.ServiceCard(`${item}互动`,`搭建用户与${item}之间的桥梁,提供便捷的互动交流服务。`)}.padding({left:16,right:16,top:12,bottom:12})}}.tabBar(item)},(item:string)=>item)}.onChange((index:number)=>{this.currentIndex=index;}).layoutWeight(1)}.width('100%').height('100%').backgroundColor(StyleConstants.BG_COLOR)}}

4.2 分段深度讲解

段落1 — 状态变量(第10-11行)
@LocalcurrentIndex:number=0;privateserviceItems:string[]=['党媒云','社区融','法律服务','健康服务'];
变量装饰器说明
currentIndex@Local当前选中 Tab 索引
serviceItemsprivate4 个服务分类名称

注意:没有@Consumer('pageStack'),因为服务模块当前没有子页面跳转需求。

段落2 — @Builder ServiceCard 卡片模板(第13-33行)
@BuilderServiceCard(title:string,description:string){Column(){Text(title)// 卡片标题.fontSize(16).fontWeight(FontWeight.Bold).fontColor(StyleConstants.TEXT_PRIMARY)Text(description)// 卡片描述.fontSize(13).fontColor(StyleConstants.TEXT_SECONDARY).margin({top:8}).maxLines(2)// 最多2行.textOverflow({overflow:TextOverflow.Ellipsis})// 超长截断}.width('100%').padding(16).backgroundColor(Color.White).borderRadius(8).shadow({radius:2,color:'#0D000000',offsetY:1})// 阴影}

卡片样式

  • 白色背景 + 圆角 8 + 阴影 → 经典的 Material Design 风格卡片
  • .padding(16)四边统一 16vp 内边距
  • .maxLines(2)+TextOverflow.Ellipsis:描述文字最多显示 2 行,超出部分以...截断

shadow 属性详解(下一节深入讲解):

.shadow({radius:2,color:'#0D000000',offsetY:1})
参数说明
radius2阴影模糊半径,值越大阴影越模糊
color'#0D000000'阴影颜色,#0D= 约 5% 透明度黑色
offsetY1阴影垂直偏移,向下 1vp(模拟光源从上方照射)
段落3 — build() 主布局(第35-73行)

布局层级

Column (根容器,BG_COLOR 背景) ├── Text('服务') ← 20号加粗标题 └── Tabs (barPosition:Start) ← 4个分类Tab └── ForEach(serviceItems) → TabContent └── Scroll ← 可滚动 └── Column (space:12) ← 3张卡片 ├── ServiceCard('${item}平台', ...) ├── ServiceCard('${item}矩阵', ...) └── ServiceCard('${item}互动', ...)

Tabs + ForEach 动态生成

Tabs({barPosition:BarPosition.Start,index:this.currentIndex}){ForEach(this.serviceItems,(item:string,index?:number)=>{TabContent(){...}.tabBar(item)// 用分类名作为Tab标签},(item:string)=>item)}

4 个分类各生成一个TabContent.tabBar(item)直接使用分类名称(“党媒云”/"社区融"等)作为标签文字。

模板字符串动态生成描述

this.ServiceCard(`${item}平台`,`提供优质的${item}内容和服务,涵盖最新资讯、深度报道、专家解读等。`)this.ServiceCard(`${item}矩阵`,`整合多渠道资源,构建全方位的${item}传播体系。`)this.ServiceCard(`${item}互动`,`搭建用户与${item}之间的桥梁,提供便捷的互动交流服务。`)

item = '党媒云'时,生成:

  • 卡片1:标题 “党媒云平台”,描述 “提供优质的党媒云内容和服务…”
  • 卡片2:标题 “党媒云矩阵”,描述 “整合多渠道资源,构建全方位的党媒云传播体系。”
  • 卡片3:标题 “党媒云互动”,描述 “搭建用户与党媒云之间的桥梁…”

每个分类 3 张卡片,4 个分类共 12 张卡片,仅用 6 行代码(3 个 @Builder 调用 × 4 个 Tab)实现。


五、卡片阴影 shadow 样式技巧

shadow是 ArkUI 提供的组件阴影属性,为卡片添加立体感和层次感。

5.1 shadow 参数详解

.shadow({radius:number,// 模糊半径(0=无模糊,越大越模糊)color:string,// 阴影颜色(含透明度)offsetX:number,// 水平偏移(正值向右,负值向左)offsetY:number// 垂直偏移(正值向下,负值向上)})

5.2 三种阴影效果对比

级别代码视觉效果适用场景
shadow({ radius: 2, color: '#0D000000', offsetY: 1 })微弱阴影,若有若无列表卡片、信息项
shadow({ radius: 4, color: '#1A000000', offsetY: 2 })明显阴影,有层次感浮动按钮、弹出面板
shadow({ radius: 8, color: '#33000000', offsetY: 4 })深阴影,悬浮感强模态框、底部弹窗

5.3 颜色透明度说明

十六进制前缀透明度十进制
#0D~5%13/255
#1A~10%26/255
#33~20%51/255
#66~40%102/255

本模块使用#0D000000(约 5% 透明度黑色),是最轻的阴影效果,适合列表中密集排列的卡片,避免阴影过于抢眼。

5.4 使用建议

  • 密集列表(如本模块):使用轻量阴影(radius:2),避免视觉干扰
  • 独立卡片(如详情页):使用中量阴影(radius:4),突出卡片存在感
  • 浮动元素(如 FAB):使用重量阴影(radius:8),强调悬浮效果
  • 避免在没有背景色差异的情况下使用阴影(白色卡片在白色背景上阴影不可见)

六、为何不需要 @Consumer(‘pageStack’)

6.1 当前状态

ServiceHome 没有子页面跳转——点击卡片不会跳转到详情页。因此不需要@Consumer('pageStack')获取 NavPathStack。

6.2 如需扩展

如果后续需要添加服务详情页,只需:

  1. pages/下创建ServiceDetail.ets,使用 NavDestination
  2. 在 ServiceHome 添加@Consumer('pageStack') pageStack!: NavPathStack
  3. 在 ServiceCard 的 onClick 中调用pushPathByName('ServiceDetail', item)
  4. 在 MainPage 的 pageMap 中注册路由
  5. 更新 Index.ets 导出

6.3 与其他模块对比

模块@Consumer子页面原因
newsNewsDetail、NewsCategory需要点击新闻查看详情
videoVideoPlayer需要点击视频播放
live仅浏览列表
personalLoginPage、MyComments需要登录和查看评论
service仅浏览卡片

七、扩展思路

7.1 添加 ServiceDetail 子页面

创建pages/ServiceDetail.ets,展示服务的详细内容:

@ComponentV2exportstruct ServiceDetail{@Consumer('pageStack')pageStack!:NavPathStack;@Localtitle:string='';aboutToAppear(){letparam=this.pageStack.getParamByName('ServiceDetail');if(param){this.title=paramasstring;}}build(){NavDestination(){...}.hideTitleBar(true)}}

7.2 WebView 集成

使用 common 模块的CommonWeb组件加载在线服务页面:

import{CommonWeb}from'common';// 在 ServiceDetail 中CommonWeb({url:'https://service.example.com'})

7.3 真实 API 对接

将模板字符串描述替换为 API 返回的真实数据,使用HttpUtil发起请求。


八、V2 装饰器使用汇总

装饰器变量/位置作用
@ComponentV2ServiceHomeV2 组件声明
@LocalcurrentIndexTab 选中索引
@BuilderServiceCard可复用卡片模板

服务模块是 V2 装饰器使用最少的模块——没有@Consumer、没有@Param、没有@Event


九、常见问题 Q&A

Q1: 为什么每个 Tab 的卡片内容结构相同?

A: 使用模板字符串`${item}平台`/`${item}矩阵`/`${item}互动`动态生成标题和描述,实现了"一套代码 × 4 个分类 = 12 张卡片"的效果。实际项目中每个分类的卡片结构和内容可能不同。

Q2:#0D000000是什么颜色格式?

A: 8 位十六进制颜色值,格式为#AARRGGBB#0D是 Alpha(透明度,约 5%),000000是 RGB(纯黑)。ArkUI 支持 8 位颜色格式。

Q3: 为什么 ServiceHome 使用BG_COLOR背景而非Color.White

A:StyleConstants.BG_COLOR是统一的页面背景色(通常是浅灰色#F5F5F5),与白色卡片形成对比,让卡片和 shadow 阴影更突出。如果背景也是白色,卡片阴影将不可见。

Q4: Scroll 组件的作用是什么?

A:Scroll让 TabContent 内容可滚动。当卡片数量超过屏幕高度时,用户可以上下滑动查看更多卡片。


十、小结

服务模块以 74 行源码实现了完整的服务入口页面,核心知识点包括:

  1. shadow 卡片阴影shadow({ radius, color, offsetY })为卡片添加立体感
  2. 模板字符串动态内容`${item}平台`用一套代码生成多个分类的卡片
  3. Tabs + ForEach:数据驱动的 Tab 动态生成模式
  4. BG_COLOR 背景 + 白色卡片:通过背景色对比突出卡片阴影效果
  5. 最精简模块结构:1 组件 + 74 行源码,适合快速理解 feature 模块的最小实现

服务模块虽然代码量最少,但shadow阴影和模板字符串动态内容是两个非常实用的技巧,在其他模块和实际项目中都有广泛应用。


需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询