尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

HarmonyOS 购物商城:消息中心页面

HarmonyOS 购物商城:消息中心页面
📅 发布时间:2026/7/9 23:34:11

前言

消息中心是 App 和用户沟通的窗口——订单状态变了通知一声,有优惠活动推送一条,物流更新提醒一下。用户不一定天天打开 App,但消息推送能把用户"拉回来"。

这篇文章拆解消息中心的实现:消息列表、未读状态、角标计数、促销卡片。
完整效果

数据模型

interfaceMsgItem{icon:string// emoji 图标title:string// 标题sub:string// 副标题/预览time:string// 时间unread:boolean// 是否未读color:string// 图标背景色count:number// 未读数量}

每个消息项包含 7 个字段。color是图标背景色——不同类型的消息用不同颜色区分(系统通知红色、物流蓝色、促销黄色)。

消息数据

@Statemessages:MsgItem[]=[{icon:'🔔',title:'系统通知',sub:'您的订单已发货...',time:'10:32',unread:true,color:'#FF6B6B',count:3},{icon:'💰',title:'优惠促销',sub:'限时秒杀!...',time:'昨天',unread:true,color:'#FECA57',count:5},{icon:'📦',title:'物流助手',sub:'快递已签收...',time:'昨天 14:20',unread:false,color:'#5DADE2',count:0},// ...]

7 条消息,3 条未读。数据是硬编码的——实际项目中从 API 加载。

消息类型的颜色编码:

  • 🔔 系统通知:红色(#FF6B6B)——紧急
  • 💰 优惠促销:黄色(#FECA57)——吸引
  • 📦 物流助手:蓝色(#5DADE2)——中性
  • ❤️ 活动通知:橙色(#E8734A)——温暖
  • ⭐ 评价邀请:黄色(#FECA57)——轻量
  • 💬 客服消息:绿色(#00B894)——友好
  • 🏪 店铺动态:紫色(#8A5DFA)——品牌

头部

Row(){Row(){SymbolGlyph($r('sys.symbol.chevron_left')).fontSize(20).fontColor([T1])}.width(34).height(34).borderRadius(17).backgroundColor('rgba(0,0,0,0.03)').justifyContent(FlexAlign.Center).onClick(()=>{router.back()})Text('消息中心').fontSize(22).fontWeight(FontWeight.Bold).fontColor(T1).margin({left:10}).layoutWeight(1)Text('全部已读').fontSize(13).fontColor(A).fontWeight(FontWeight.Medium)}

头部三个元素:返回按钮 + 标题 + "全部已读"按钮。

"全部已读"的实现:

Text('全部已读').fontSize(13).fontColor(A).fontWeight(FontWeight.Medium)

目前只是显示文字,没有绑定onClick。实际项目中需要遍历所有消息,把unread设为false,count设为0。

消息列表

ForEach(this.messages,(msg:MsgItem,idx:number)=>{Column(){Row(){// 图标角标// 消息信息// 箭头}if(idx<this.messages.length-1){Divider().strokeWidth(0.5).color('#F0EEF4').margin({left:78,right:16})}}.width('100%').backgroundColor(CW).onClick(()=>{this.openChat(msg)})})

每条消息是一个 Row,点击后调用openChat。

分割线的左边距

Divider().strokeWidth(0.5).color('#F0EEF4').margin({left:78,right:16})

分割线左边距 78px——跳过图标区域(50px 图标 + 12px 间距 + 16px 内边距 ≈ 78px)。这样分割线不会穿过图标,视觉更整洁。

图标角标

Stack({alignContent:Alignment.TopEnd}){Column(){Text(msg.icon).fontSize(22)}.width(50).height(50).borderRadius(15).backgroundColor(msg.color+'15').justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)if(msg.count>0){Row(){Text(msg.count>99?'99+':msg.count.toString()).fontSize(9).fontWeight(FontWeight.Bold).fontColor(Color.White)}.width(18).height(18).borderRadius(9).backgroundColor(A).justifyContent(FlexAlign.Center).alignItems(VerticalAlign.Center).position({x:-2,y:-4})}}

图标的结构:Stack 叠加 [彩色背景圆角方块 + emoji] 和 [红色圆形计数]。

背景色的透明度处理:

.backgroundColor(msg.color+'15')

msg.color是'#FF6B6B',拼上'15'变成'#FF6B6B15'——这是 8 位 hex 颜色,后两位15是 alpha 通道(约 8% 不透明度)。效果是极淡的彩色背景。

计数的position:

.position({x:-2,y:-4})

计数徽章在图标右上角,偏左 2px、偏上 4px。这个位置是手动调的——太右会超出容器,太下会挡住 emoji。

99+ 的处理:

msg.count>99?'99+':msg.count.toString()

超过 99 显示"99+"——避免角标太宽撑坏布局。

消息信息

Column(){Row(){Text(msg.title).fontSize(15).fontWeight(msg.unread?FontWeight.Bold:FontWeight.Medium).fontColor(msg.unread?T1:T2).layoutWeight(1)Text(msg.time).fontSize(11).fontColor(T3)}Text(msg.sub).fontSize(12).fontColor(T2).maxLines(2).textOverflow({overflow:TextOverflow.Ellipsis}).margin({top:4})}.alignItems(HorizontalAlign.Start).margin({left:12}).layoutWeight(1)

未读状态的视觉区分:

  • 未读:标题粗体 + 深色(T1)
  • 已读:标题中等字重 + 灰色(T2)

用户一眼就能看出哪些消息没看过。

openChat

privateopenChat(msg:MsgItem):void{msg.unread=falsemsg.count=0router.pushUrl({url:'pages/MessageDetail',params:{'title':msg.title,'sub':msg.sub,'time':msg.time,'icon':msg.icon,'color':msg.color}asRecord<string,Object>})}

点击消息时:

  1. 把unread设为false,count设为0——标记已读
  2. 跳转 MessageDetail 页面,传递消息信息

直接修改msg.unread有效吗?

msg是this.messages数组中的对象引用。直接修改msg.unread会修改原数组——但@State不会检测到对象内部的变化,UI 不会自动更新。

这是一个潜在的 bug——点击后标题不会从粗体变回普通字重。需要refresh()或者重新赋值this.messages = [...this.messages]。

促销卡片

Column(){Row(){Column(){}.width('100%').height(80).borderRadius(16).linearGradient({angle:135,colors:[[A,0],['#FF9F43',1]]})Column(){Text('🎉 618年中大促').fontSize(16).fontWeight(FontWeight.Bold).fontColor(Color.White)Text('全场低至1折 · 领券再减').fontSize(11).fontColor('rgba(255,255,255,0.7)').margin({top:4})}.position({x:16,y:16})}.width('100%').height(80)}.onClick(()=>{router.pushUrl({url:'pages/ProductList',params:{'category':'全部分类'}asRecord<string,Object>})})

消息列表底部加了一个促销卡片——渐变背景 + 文案,点击跳转商品列表。

促销卡片的位置:

它在ForEach之后、Scroll之内——用户滚到消息列表底部才能看到。这是一个"钩子"——用户看完所有消息后,看到促销卡片,可能点进去逛逛。

为什么用 Stack 结构的 Row?

渐变背景是一个空 Column,文字用position({ x: 16, y: 16 })定位在左上角。这样文字浮在渐变背景上方,视觉效果像一个完整的横幅。

踩坑记录

1. 消息已读的状态同步

msg.unread=falsemsg.count=0

直接修改对象属性不会触发@State更新。需要:

privateopenChat(msg:MsgItem,idx:number):void{constupdated=[...this.messages]updated[idx]={...msg,unread:false,count:0}this.messages=updated router.pushUrl(...)}

2. 分割线的左边距计算

Divider().margin({left:78,right:16})

78px = 16px(Row padding-left)+ 50px(图标宽度)+ 12px(图标和文字间距)。如果图标宽度或间距变了,分割线的左边距也要跟着调。

3. 消息列表的性能

7 条消息用ForEach一次性渲染没问题。但如果消息数量多(100+),需要考虑懒加载。

4. "全部已读"按钮的实现

目前"全部已读"没有onClick。实现思路:

Text('全部已读').onClick(()=>{for(leti=0;i<this.messages.length;i++){this.messages[i].unread=falsethis.messages[i].count=0}this.messages=[...this.messages]// 触发 UI 更新})

5. 促销卡片的点击跳转

.onClick(()=>{router.pushUrl({url:'pages/ProductList',params:{'category':'全部分类'}asRecord<string,Object>})})

促销卡片跳转到商品列表页——和首页底部导航的"分类"按钮一样的目标。用户从消息中心进入购物场景。

写在最后

消息中心的设计核心是"信息分层"——未读消息用粗体和角标吸引注意力,已读消息退居二线。颜色编码帮助用户快速识别消息类型(红色=紧急,蓝色=物流,黄色=促销)。

促销卡片放在消息列表底部是一个巧妙的设计——用户看完所有消息后自然看到促销,从"查看通知"无缝切换到"浏览商品"。消息中心不只是通知的容器,也是流量的入口。

相关新闻

  • ESP-01S 继电器模块 3 种供电方案实测:5V USB、12V适配器与220V直连安全指南
  • MP2672A双节锂电池充电管理与STM32F302VC实现
  • 提示词工程实战指南:从零掌握与大模型高效对话的核心技术

最新新闻

  • 郑州水电维修口碑:10家专业电工团队分享,持证上岗 - 星际AI
  • 2026年7月9日——武汉汛期防水攻略:老房/高层/临江地下室三种漏法 - 捷修防水
  • 2026独山黄金回收避坑指南:报价透明与当场到账才是硬道理,这三家三十年老店全境免费上门 - 福金阁黄金回收
  • 2026年7月最新亨得利官方名表服务中心|最新电话和维修门店地址权威信息声明 - 亨得利官方博客
  • 2026年西安别墅装修公司推荐:五家优选设计能力解析 - 科技焦点
  • CPPM vs SCMP考试难度排行Top1揭秘(2026.07) - 众智商学院cppm官方

日新闻

  • OpenClaw本地化部署:xParse文档解析引擎实战指南
  • 蓝牙 5.4 协议栈深度解析:从 HCI 到 L2CAP 的 7 层数据流
  • PyTorch nn.CrossEntropyLoss 实战:3种权重设置与标签平滑对比(附代码)

周新闻

  • 基于YOLOv12的番茄成熟度智能检测系统开发
  • 终极RimWorld模组管理指南:用RimSort告别模组冲突烦恼
  • AI Agent框架开发:从理论到实践的完整指南

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号