[江鸟中原] 鸿蒙——小易购物app的设计与开发
小易购物APP是一款基于鸿蒙系统的移动购物应用,提供完整的购物流程体验。核心功能包括:1)账号管理(登录、注册、密码找回);2)首页导航(轮播图、分类栏);3)商品展示(双列布局、排行榜);4)购物流程(购物车、订单管理);5)个人中心(地址管理、收藏夹)。应用采用标准化交互设计(44×44返回按钮、即时反馈),优化了数据校验、动态加载等技术实现,通过色彩区分和分类导航提升用户体验。项目注重操作流
目录
一.引言
我在这篇文章中分享了我的鸿蒙移动应用开发课程的期末大作业——小易购物app。项目基于ArkUI声明式开发框架构建,聚焦电商场景UI界面实现,所有展示数据均存储于本地,未涉及真实网络数据交互。通过搭建轮播图、商品列表、底部导航等核心模块,我系统掌握了ArkUI组件组合、布局设计等关键技能,切实感受到其简洁语法与高效开发优势。在此分享这份实践成果,为初识ArkUI的开发者提供直观参考,也期待与大家交流优化思路,共同进步。
二.开发工具和框架
1. 核心开发工具:DevEco Studio 全流程应用,覆盖项目创建、编码、编译、调试等环节,运用模拟器完成多设备适配测试,借助调试工具高效排障,提升开发连贯性。
2. 基础架构构建:依托 HarmonyOS SDK 搭建项目底层,熟练调用系统 API 与能力库,完成设备适配、权限配置,确保项目符合鸿蒙规范,筑牢业务开发基础。
3. UI 开发框架:基于 ArkUI 声明式特性实现多端适配,运用组件库与布局方案,快速搭建一致性强、交互流畅的 UI 界面,提升开发效率与视觉统一性。
4. 业务支撑组件:灵活运用 Ability、分布式数据管理、事件总线等组件,实现页面管理、跨设备数据同步与组件通信,高效支撑复杂业务落地。
5. 开发规范与效率优化:严格遵循鸿蒙开发规范,封装复用 ArkUI 组件,减少重复开发,提升代码复用性与迭代效率,夯实工具与框架综合应用能力。
项目框架:
三. 项目介绍
小易购物APP功能布局清晰,覆盖购物全流程。登录注册简洁,多种验证方式助力快速安全登录。首页精选爆款、新品与限时优惠,多元品类直观呈现,方便高效发现好物。购物车支持一键收藏商品,下单便捷。排行榜按销量排序,为选购提供可靠参考。“我的”页面整合实用服务,购物地址可新增、编辑及设置默认;我的最爱板块可收藏商品并实时关注动态。各功能衔接流畅,打造一站式舒适购物体验。
四. 功能介绍
4.1. 登录功能
登录页面上展示 Logo 与 “欢迎登录” 标题,用户可在指定输入框填写用户名和密码(密码隐藏输入,均限 6 位),输入内容实时日志记录。点击蓝色 “注册” 文字,可快速跳转对应的注册页面。底部胶囊型登录按钮点击有反馈,若输入为空,将弹出 3 秒提示;输入完整则跳转主页面,异常情况会捕获错误并日志提示。输入框样式统一,全屏适配,从输入到跳转流程清晰,为用户提供便捷稳定的登录操作体验。
4.2.忘记密码功能
这是鸿蒙应用的“忘记密码”页面,专为账号密码找回设计,操作简洁且校验贴心。顶部白色导航栏左侧,是44×44像素的透明返回按钮,点击内置24×24像素图标即可返回上一页;中间“忘记密码”标题居中粗显,明确页面用途。下方输入区域提示“请输入您绑定的手机号”,输入框限定数字输入,搭配白色背景与灰色占位符,清晰易操作。底部90%宽度的蓝色“确认”按钮,点击后会校验手机号:非11位则提示“请输入有效的手机号”,验证通过则弹窗提示并在1.5秒后跳转首页。整体浅灰背景搭配规整布局,操作流程顺畅,保障密码找回便捷安全。
4.3. 注册功能
这是鸿蒙系统的用户注册页面,操作简单直观!页面顶部展示Logo与“用户注册”标题,用户需填写用户名及两次密码(均限6位,密码隐藏输入),输入内容实时日志记录。点击蓝色“去登录”可跳转登录页,底部蓝色胶囊注册按钮点击有反馈。若信息未填全,将提示“用户名或密码不能为空”;两次密码不一致则弹窗提醒,注册成功后1.5秒自动跳转登录页,全程操作流畅,校验贴心,为新用户提供便捷注册体验。
4.4. 首页页面
这是鸿蒙应用的底部导航主页面,操作便捷直观!页面底部设有“首页”“精选”“我的”三个功能入口,每个入口搭配专属图标与文字,清晰易辨。点击对应导航项,即可快速切换至Home、choice、Mine三个核心页面,切换动画流畅(时长400毫秒)。导航栏占满全屏宽度,高度适配舒适,图标与文字大小搭配协调,视觉体验佳。无需复杂操作,通过底部一键切换,就能轻松访问应用各核心功能模块,为用户提供高效便捷的页面导航体验。
4.4.1 图片轮播组件
这是鸿蒙应用的图片轮播组件,操作无额外交互更省心!内置5张图片,默认从首张开始,5秒自动切换,切换动画时长3秒,支持循环播放。轮播图占95%宽度、160高度,顶部留5vp边距,隐藏指示器,整体简洁流畅,适配直观展示图片需求。
4.4.2 顶部导航组件
这是鸿蒙应用的顶部导航组件,操作直观便捷!包含“首页”“精选”“排行榜”“购物车”“我的”五个入口,均搭配图标与文字,均匀分布且占满全屏。点击对应选项,即可快速跳转至关联页面,布局清晰、交互流畅,轻松切换应用核心功能。
4.4.3 首页展示图
4.5. 精选页面
这是鸿蒙应用的商品分类浏览页面,操作直观且功能丰富!顶部设有横向滚动的分类导航栏,包含电子产品、生活用品、服装、时蔬、特价商品五大类,选中项以橙红底色+白色文字高亮区分,未选中项为灰色底黑字,清晰易辨。点击对应分类,下方网格区域即刻切换展示该类商品,无需额外加载步骤。商品以双列网格布局呈现,每张卡片包含图片、名称、价格,名称超出两行自动省略,价格标红醒目。卡片带轻微阴影与圆角,点击可跳转至商品详情页。页面整体背景简洁,分类导航支持横向滑动,商品区域可纵向滚动,分类切换流畅,商品展示清晰,为用户提供便捷的分类筛选与商品浏览体验。
4.5.1 电子产品页面
含手机、耳机等,科技含量高,兼具通讯、娱乐功能,更新迭代快,如无线蓝牙耳机、智能手表等,提升生活便捷性。
4.5.2 生活用品页面
涵盖厨具、收纳等实用好物,像料理锅、收纳箱,注重实用性与环保,助力提升居家生活品质。
4.5.3 服装页面
含T恤、连衣裙等,风格多样适配不同场景,兼顾时尚与舒适,春秋风衣、夏季短袖均为热门品类。
4.5.4 时蔬页面
以新鲜果蔬为主,如荔枝、草莓,强调天然健康,部分为有机品类,是日常饮食的重要组成部分
4.5.5 特价商品页面
含清仓、临期等商品,价格低廉,如旧款耳机、断码服饰,性价比突出,满足实惠消费需求。
4.6. 我的页面
这是鸿蒙应用的“我的”个人中心页面,布局清晰、操作便捷!页面顶部是“我的”标题导航栏,下方展示用户头像、昵称“张三”及绑定邮箱,信息直观明了。中间功能区包含“我的订单”“我的收藏”“收货地址”三个核心入口,均为通栏设计,点击分别跳转至购物车、收藏页、地址管理页,满足订单查询、收藏管理、地址维护需求。底部设有“退出登录”按钮,占据90%页面宽度,点击即可返回登录页。整体采用白色功能块搭配浅灰色背景,视觉清爽,各区域间距合理,操作逻辑简单易懂,从个人信息查看、功能入口使用到退出登录,全程流程顺畅,为用户提供便捷的个人中心管理体验。
4.6.1 个人信息功能
位于导航栏下方,左侧展示圆形头像,右侧清晰呈现昵称“张三”及绑定邮箱“11111@qq.com”。信息排布紧凑有序,视觉层次分明,让用户能快速确认个人账号信息,直观且易读。
4.6.2 我的订单页面
采用通栏设计融入功能列表,视觉上简洁易识别。点击后直接跳转至购物车页面,打破功能与操作的割裂感,方便用户快速查询订单状态、商品明细及物流信息,为订单管理提供直观且高效的入口,满足日常购物后的订单追踪需求。
4.6.3 我的收藏页面
以统一的通栏样式呈现,与其他功能入口形成视觉呼应。点击即可进入专属收藏页,用户可集中查看曾标记的心仪商品,无需重新搜索,便于对比筛选或直接购买,有效留存用户兴趣偏好,提升购物决策效率。
4.6.4 收货地址页面
通栏布局保证操作区域充足,点击后跳转至地址管理页面。在此用户可添加新地址、编辑现有地址或设置默认地址,解决网购中地址填写繁琐的问题,确保下单时地址信息准确无误,为顺畅购物提供基础保障。
4.6.5 退出登录功能
独立设置在页面底部,采用辨识度高的按钮形态,与功能列表形成区分。点击后即刻跳转回登录页面,操作响应迅速,既满足用户切换账号的需求,又能通过返回登录页保障账号安全,避免信息泄露风险。
4.7. 商品排行榜页面
这是鸿蒙应用的“购买TOP10”商品排行榜页面,功能明确且操作便捷。顶部为白色导航栏,左侧是44×44像素的透明背景按钮,内置24×24像素返回图标,点击即可返回上一页;中间“购买TOP10”标题居中,字体粗重醒目。主体是纵向滚动的商品列表,展示销量前10商品,1-3名排名文字为橙红色,4-10名为深灰色,区分清晰。每栏含排名、60×60像素商品图、名称、红底价格及灰色销量信息,点击任意商品栏可跳转至对应详情页。页面以浅灰为底,白色商品栏间隔排布,交互流畅,助力快速锁定热门好物。
4.8.购物车功能
这是鸿蒙应用的“我的购物车”页面,操作便捷且功能实用。顶部白色导航栏左侧,是44×44像素的透明返回按钮,点击图标即可返回上一页;中间“我的购物车”标题居中醒目。页面主体展示两款商品,均为“图片+信息+数量控制”布局,商品图60×60像素清晰呈现,价格标红突出。每款商品右侧设有“-”“+”按钮,点击可调整数量(数量不低于1),实时联动总价计算。底部结算栏显示实时总价,右侧橙红色“结算”按钮点击后弹出“结算成功”提示。整体浅灰背景搭配白色商品栏,布局规整,从返回导航、数量调整到结算,全程操作流畅,满足购物车核心使用需求。
4.9.点击返回功能
点击返回功能是保障用户操作连贯性的核心交互入口,设计贴心且操作零门槛。其载体为导航栏侧的专属按钮,尺寸固定为44×44像素,采用全透明背景设计,仅内嵌24×24像素的返回图标,既清晰易识别,又不干扰界面整体视觉。用户无需精准定位,轻触按钮区域即可触发返回指令,快速回到上一界面,避免在当前操作流程中滞留。该功能为用户提供灵活的操作退路,与当前页面核心业务流程形成互补,让整体交互更灵活,大幅提升操作体验的流畅度。
1.点击首页的排行榜,进入排行榜页面

2.点击返回箭头,退出排行榜页面进入上一个页面
五. 项目总结
一、账号管理核心功能:应用以“购物服务+账号管理”为核心,账号端构建完整安全体系,涵盖注册登录、密码找回等功能。密码找回页面通过手机号校验身份,输入框限定数字格式,系统自动核验11位号码有效性,避免无效操作;所有账号相关页面均设明确操作指引,大幅降低用户使用门槛。
二、购物服务核心模块:购物端形成“浏览-筛选-决策-结算”闭环,包含五大品类商品分类浏览、销量TOP10排行、购物车管理等模块。分类筛选助力快速定位需求,销量排行通过1-3名橙红、4-10名深灰的色彩区分,直观呈现热门商品;购物车支持商品数量增减(最低1件)与实时总价计算,结算后即时反馈结果。
三、设计与体验优势:项目设计极具统一性,所有页面采用“顶部导航+主体内容+功能按钮”布局,顶部左侧标配44×44像素透明返回按钮,内嵌24×24像素图标,保障操作连贯。视觉上白块配浅灰背景,关键信息用橙红或蓝色突出,交互响应迅速,提供直观高效的使用体验。
在本次项目的过程中,我收获颇丰。技术层面,通过实操深化了对核心业务场景的理解,熟练运用相关工具解决了数据处理、流程优化中的实际问题,编程与逻辑思维能力得到显著提升。协作上,在跨部门沟通与团队分工中,学会了精准表达需求、高效对接资源,也懂得了换位思考与互补协作的重要性。面对项目推进中的突发问题,我逐渐养成了拆解难题、复盘总结的习惯,抗压能力与问题解决效率大幅提高。此外,对项目全流程的把控让我建立了更系统的工作思维,严谨细致的态度也在反复打磨中愈发坚定。这些经验将成为我后续工作的重要积淀,激励我持续精进、稳步前行。
附录主要代码
1.登录页面
import router from '@ohos.router'
import promptAction from '@ohos.promptAction';
@Entry
@Component
struct Login {
@State message: string = '欢迎登录';
@State user: string = '';
@State password: string = ''
build() {
Row() {
Column() {
//Logo
Image($r('app.media.Logo'))
.width(100)
.height(20)
.margin({ bottom: '20' })
//欢迎登录
Text(this.message)
.fontSize('30')
.fontWeight(FontWeight.Bold)
//用户名和密码
TextInput({ placeholder: '请输入用户名' })
.inputStyle()
.onChange(data => {
this.user = data;
console.info('user:' + data)
})
TextInput({ placeholder: '请输入密码' })
.type(InputType.Password)//输入类型
.inputStyle()
.onChange(data => {
this.password = data;
console.info('password:' + data)
})
// --- 修改点:文字提示行 ---
Row(){
// 移除了“其他登录方式”相关代码
// 新增“注册”选项
Text('忘记密码')
.fontSize('18fp')
.fontColor(Color.Blue)
.onClick(() => {
// // 这里可以添加跳转到注册页面的逻辑
// promptAction.showToast({ message: '' });
router.pushUrl({ url: 'view/number' });
})
Text('注册')
.fontSize('18fp')
.fontColor(Color.Blue)
.onClick(() => {
// // 这里可以添加跳转到注册页面的逻辑
// promptAction.showToast({ message: '' });
router.pushUrl({ url: 'pages/RegisterPage' });
})
}
.width('100%')
.justifyContent(FlexAlign.SpaceAround)
//登录
Button('登录',{type:ButtonType.Capsule,stateEffect:true})
.width('90%')
.margin('10')
.onClick(()=>{
//路由跳转
if(this.user==''||this.password==''){
promptAction.showToast({
message:'用户名或密码不能为空',
duration:3000,
bottom:'60'
})
}else {
router.pushUrl({
url:'pages/MainPage'
}).catch((error:Error)=>{
console.error(`跳转失败: ${error.message}`);
})
}
})
}
.width('100%')
}
.height('100%')
}
}
//添加公共样式函数
//@Extend装饰器
//@Extend(组件名称)function 样式名称
@Extend(TextInput) function inputStyle(){
.placeholderColor(0x00001)
.maxLength(6)
.padding('12')
.margin('10')
}
2.注册页面
import router from '@ohos.router';
import promptAction from '@ohos.promptAction';
@Entry
@Component
struct RegisterPage {
@State message: string = '用户注册';
@State username: string = '';
@State password: string = '';
@State confirmPassword: string = '';
build() {
Row() {
Column() {
//Logo
Image($r('app.media.Logo'))
.width(100)
.height(20)
.margin({ bottom: '20' })
//标题
Text(this.message)
.fontSize('30')
.fontWeight(FontWeight.Bold)
.margin({ bottom: '20' })
//用户名和密码输入框
TextInput({ placeholder: '请输入用户名' })
.inputStyle()
.onChange(data => {
this.username = data;
console.info('username:' + data);
})
TextInput({ placeholder: '请输入密码' })
.type(InputType.Password) // 输入类型为密码
.inputStyle()
.onChange(data => {
this.password = data;
console.info('password:' + data);
})
TextInput({ placeholder: '请确认密码' })
.type(InputType.Password) // 输入类型为密码
.inputStyle()
.onChange(data => {
this.confirmPassword = data;
console.info('confirmPassword:' + data);
})
// 文字提示
Row() {
Text('已有账号?')
.fontSize('18fp')
.fontColor('#666666')
Text('去登录')
.fontSize('18fp')
.fontColor(Color.Blue)
.onClick(() => {
router.pushUrl({ url: 'pages/LoginPage' });
})
}
.width('100%')
.justifyContent(FlexAlign.Center)
.margin({ top: '10' })
// 注册按钮
Button('注册', { type: ButtonType.Capsule, stateEffect: true })
.width('90%')
.margin('10')
.backgroundColor(Color.Blue) // 改为蓝色
.fontColor('#ffffff')
.onClick(() => {
// 路由跳转前的简单校验
if (this.username === '' || this.password === '' || this.confirmPassword === '') {
promptAction.showToast({
message: '用户名或密码不能为空',
duration: 3000,
bottom: '60'
});
} else if (this.password !== this.confirmPassword) {
promptAction.showToast({
message: '两次输入的密码不一致',
duration: 3000,
bottom: '60'
});
} else {
// 模拟注册成功,跳转到登录页
promptAction.showToast({ message: '注册成功' });
setTimeout(() => {
router.pushUrl({ url: 'pages/LoginPage' });
}, 1500);
}
})
}
.width('100%')
.padding('20')
}
.height('100%')
.backgroundColor('#f5f5f5')
}
}
// 添加公共样式函数
// @Extend装饰器
@Extend(TextInput) function inputStyle() {
.placeholderColor(0x000002)
.maxLength(6)
.padding('12')
.margin('10')
}
3.首页
import router from '@ohos.router'
import Home from '../view/HomePage'
import choice from '../view/choicePage'
import Mine from '../view/MinePage'
@Entry
@Component
struct Main {
@State message: string = '首页';
private controller:TabsController=new TabsController();
@Builder TabBuilder1(){
Column(){
Image($r('app.media.home2'))
.width(25)
.height(25)
Text('首页')
.fontSize(10)
.fontWeight(500)
}
.width('100%')
}
@Builder TabBuilder2(){
Column(){
Image($r('app.media.choice3'))
.width(25)
.height(25)
Text('精选')
.fontSize(10)
.fontWeight(500)
}
.width('100%')
}
@Builder TabBuilder3(){
Column(){
Image($r('app.media.mine2'))
.width(25)
.height(25)
Text('我的')
.fontSize(10)
.fontWeight(500)
}
.width('100%')
}
build() {
Row(){
Tabs({barPosition:BarPosition.End}){
TabContent(){
Home()
}.tabBar(this.TabBuilder1())
TabContent(){
choice()
}.tabBar(this.TabBuilder2())
TabContent(){
Mine()
}.tabBar(this.TabBuilder3())
}
.vertical(false)//首页的位置
.barWidth('100%')
.barHeight('37')
.animationDuration(400)
}
.height('100%')
}
}
4.精选页面
import router from '@ohos.router';
@Entry
@Component
export default struct Choice {
// 使用一个状态变量来记录当前选中的分类索引
@State selectedTabIndex: number = 0;
build() {
Column() {
// --- 1. 顶部手动写的分类导航栏 ---
Scroll() {
Row() {
// 分类1:电子产品
Text('电子产品')
.fontSize(16)
.fontColor(this.selectedTabIndex === 0 ? '#ffffff' : '#333333')
.backgroundColor(this.selectedTabIndex === 0 ? '#ff4400' : '#f1f1f1')
.padding({ left: 15, right: 15, top: 8, bottom: 8 })
.borderRadius(20)
.margin({ right: 10 })
.onClick(() => {
this.selectedTabIndex = 0;
})
// 分类2:生活用品
Text('生活用品')
.fontSize(16)
.fontColor(this.selectedTabIndex === 1 ? '#ffffff' : '#333333')
.backgroundColor(this.selectedTabIndex === 1 ? '#ff4400' : '#f1f1f1')
.padding({ left: 15, right: 15, top: 8, bottom: 8 })
.borderRadius(20)
.margin({ right: 10 })
.onClick(() => {
this.selectedTabIndex = 1;
})
// 分类3:服装
Text('服装')
.fontSize(16)
.fontColor(this.selectedTabIndex === 2 ? '#ffffff' : '#333333')
.backgroundColor(this.selectedTabIndex === 2 ? '#ff4400' : '#f1f1f1')
.padding({ left: 15, right: 15, top: 8, bottom: 8 })
.borderRadius(20)
.margin({ right: 10 })
.onClick(() => {
this.selectedTabIndex = 2;
})
// 分类4:时蔬
Text('时蔬')
.fontSize(16)
.fontColor(this.selectedTabIndex === 3 ? '#ffffff' : '#333333')
.backgroundColor(this.selectedTabIndex === 3 ? '#ff4400' : '#f1f1f1')
.padding({ left: 15, right: 15, top: 8, bottom: 8 })
.borderRadius(20)
.margin({ right: 10 })
.onClick(() => {
this.selectedTabIndex = 3;
})
// 分类5:特价商品
Text('特价商品')
.fontSize(16)
.fontColor(this.selectedTabIndex === 4 ? '#ffffff' : '#333333')
.backgroundColor(this.selectedTabIndex === 4 ? '#ff4400' : '#f1f1f1')
.padding({ left: 15, right: 15, top: 8, bottom: 8 })
.borderRadius(20)
.margin({ right: 10 })
.onClick(() => {
this.selectedTabIndex = 4;
})
}
.padding(10)
}
.scrollable(ScrollDirection.Horizontal)
.width('100%')
.backgroundColor('#ffffff')
.shadow({ radius: 2, color: '#00000010', offsetY: 2 })
// --- 2. 根据选中的索引,手动显示对应的商品网格 ---
Scroll() {
// 使用 if / else if 来判断显示哪个分类的商品
if (this.selectedTabIndex === 0) {
// --- 电子产品 (使用本地图片) ---
Grid() {
GridItem() { this.ProductCard('无线蓝牙耳机 超长续航', '¥79.9', $r('app.media.51'), 1) }
GridItem() { this.ProductCard('智能手表 心率监测', '¥199.0', $r('app.media.52'), 2) }
GridItem() { this.ProductCard('便携式充电宝 20000mAh', '¥69.9', $r('app.media.53'), 3) }
GridItem() { this.ProductCard('超薄全面屏手机', '¥2999.0', $r('app.media.54'), 4) }
GridItem() { this.ProductCard('高清投影仪 家用', '¥1299.0', $r('app.media.55'), 5) }
GridItem() { this.ProductCard('机械键盘 青轴', '¥249.0', $r('app.media.56jpg'), 6) }
GridItem() { this.ProductCard('平板电脑 二合一', '¥6799.0', $r('app.media.57'), 7) }
GridItem() { this.ProductCard('智能音箱', '¥199.0', $r('app.media.58'), 8) }
}
.columnsTemplate('1fr 1fr')
.columnsGap(10)
.rowsGap(10)
.padding(10)
.width('100%')
} else if (this.selectedTabIndex === 1) {
// --- 生活用品 (使用本地图片) ---
Grid() {
GridItem() { this.ProductCard('超值特惠 家用抽纸10包', '¥19.9', $r('app.media.61jpg'), 9) }
GridItem() { this.ProductCard('网红爆款 全自动雨伞', '¥39.9', $r('app.media.62'), 10) }
GridItem() { this.ProductCard('家用多功能料理锅', '¥129.0', $r('app.media.63'), 11) }
GridItem() { this.ProductCard('高效除螨仪', '¥669.0', $r('app.media.64'), 12) }
GridItem() { this.ProductCard('香薰机 超声波', '¥79.0', $r('app.media.65'), 13) }
GridItem() { this.ProductCard('真空保鲜盒套装', '¥59.0', $r('app.media.66'), 14) }
GridItem() { this.ProductCard('电动牙刷', '¥129.0', $r('app.media.67'), 15) }
GridItem() { this.ProductCard('收纳箱 大号', '¥49.0', $r('app.media.68'), 16) }
}
.columnsTemplate('1fr 1fr')
.columnsGap(10)
.rowsGap(10)
.padding(10)
.width('100%')
} else if (this.selectedTabIndex === 2) {
// --- 服装 (使用本地图片) ---
Grid() {
GridItem() { this.ProductCard('夏季短袖T恤 宽松百搭款', '¥74', $r('app.media.71jpg'), 17) }
GridItem() { this.ProductCard('时尚牛仔裤 直筒修身', '¥59.9', $r('app.media.72jpg'), 18) }
GridItem() { this.ProductCard('女士连衣裙 夏季新款', '¥89.0', $r('app.media.73'), 19) }
GridItem() { this.ProductCard('舒适运动套装', '¥119.0', $r('app.media.77jpg'), 20) }
GridItem() { this.ProductCard('春秋季薄款风衣', '¥199.0', $r('app.media.81'), 21) }
GridItem() { this.ProductCard('男士休闲衬衫', '¥79.0', $r('app.media.76'), 22) }
GridItem() { this.ProductCard('保暖内衣套装', '¥69.0', $r('app.media.74jpg'), 23) }
GridItem() { this.ProductCard('潮流帆布鞋', '¥59.0', $r('app.media.78'), 24) }
}
.columnsTemplate('1fr 1fr')
.columnsGap(10)
.rowsGap(10)
.padding(10)
.width('100%')
} else if (this.selectedTabIndex === 3) {
// --- 时蔬 (使用本地图片) ---
Grid() {
GridItem() { this.ProductCard('新鲜水果 妃子笑荔枝500g', '¥19.9', $r('app.media.82'), 25) }
GridItem() { this.ProductCard('有机蔬菜组合 5斤装', '¥35.0', $r('app.media.83jpg'), 26) }
GridItem() { this.ProductCard('精品西红柿 2斤', '¥12.9', $r('app.media.84'), 27) }
GridItem() { this.ProductCard('鲜嫩黄瓜花 3斤', '¥33.8', $r('app.media.91jpg'), 28) }
GridItem() { this.ProductCard('进口香蕉 1把', '¥12.8', $r('app.media.92jpg'), 29) }
GridItem() { this.ProductCard('时令草莓 500g', '¥39.9', $r('app.media.94'), 30) }
GridItem() { this.ProductCard('山东大樱桃 2斤', '¥89.0', $r('app.media.95'), 31) }
GridItem() { this.ProductCard('清脆甜梨 4斤', '¥25.0', $r('app.media.98'), 32) }
}
.columnsTemplate('1fr 1fr')
.columnsGap(10)
.rowsGap(10)
.padding(10)
.width('100%')
} else if (this.selectedTabIndex === 4) {
// --- 特价商品 (使用本地图片) ---
Grid() {
GridItem() { this.ProductCard('清仓特价 旧款耳机', '¥29.9', $r('app.media.101jpg'), 33) }
GridItem() { this.ProductCard('临期食品 零食大礼包', '¥19.9', $r('app.media.102'), 34) }
GridItem() { this.ProductCard('断码T恤 买一送一', '¥39.0', $r('app.media.103'), 35) }
GridItem() { this.ProductCard('瑕疵品 杯子', '¥5.0', $r('app.media.105jpg'), 36) }
GridItem() { this.ProductCard('库存尾货 蓝牙音箱', '¥49.0', $r('app.media.106jpg'), 37) }
GridItem() { this.ProductCard('过季外套 特价', '¥89.0', $r('app.media.107'), 38) }
GridItem() { this.ProductCard('试用装化妆品', '¥19.0', $r('app.media.109'), 39) }
GridItem() { this.ProductCard('促销礼品 马克杯', '¥9.9', $r('app.media.110'), 40) }
}
.columnsTemplate('1fr 1fr')
.columnsGap(10)
.rowsGap(10)
.padding(10)
.width('100%')
}
}
.flexGrow(1)
.width('100%')
}
.width('100%')
.height('100%')
.backgroundColor('#f9f9f9')
}
/**
* 封装一个商品卡片组件,避免重复代码
* @param name 商品名称
* @param price 商品价格
* @param imageUrl 商品图片链接/本地图片资源
* @param id 商品ID
*/
@Builder ProductCard(name: string, price: string, imageUrl: Resource | string, id: number) {
Column() {
Image(imageUrl)
.width('100%')
.height(150)
.objectFit(ImageFit.Cover)
Text(name)
.fontSize(14)
.margin(5)
.flexGrow(1)
.maxLines(2)
.textOverflow({ overflow: TextOverflow.Ellipsis })
Text(price)
.fontSize(16)
.fontColor('#ff4400')
.margin(5)
.alignSelf(ItemAlign.Start)
}
.padding(5)
.backgroundColor('#fff')
.borderRadius(8)
.shadow({ radius: 3, color: '#00000008', offsetY: 2 })
.onClick(() => {
router.pushUrl({ url: `pages/ProductDetail?id=${id}` });
})
}
}
5.个人中心页面
import router from '@ohos.router';
@Entry
@Component
export default struct Mine {
build() {
// 根容器:垂直排列所有内容
Column() {
// --- 顶部导航栏 (之前已添加) ---
Row() {
Text('我的')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.flexGrow(1)
.textAlign(TextAlign.Center)
}
.width('100%')
.backgroundColor('#ffffff')
.padding({ top: 5 })
// 2. 用户信息区域
Row() {
Image($r('app.media.1')) // 头像
.width(50)
.height(50)
.borderRadius(25)
Column() { // 文字信息
Text('张三')
.fontSize(16)
Text('11111@qq.com')
.fontSize(12)
.fontColor('#666666')
}
}
.padding(15)
.backgroundColor('#ffffff')
.width('100%')
// 3. 功能列表
Column() {
// 我的订单 (之前已修改)
Row() {
Text('我的订单')
.fontSize(14)
.flexGrow(1)
}
.padding(15)
.width('100%')
.onClick(() => {
router.pushUrl({ url: 'view/cart' }); // 跳转到购物车
})
// --- 主要修改点:我的收藏 ---
Row() {
Text('我的收藏')
.fontSize(14)
.flexGrow(1) // 让文字占据左侧空间
}
.padding(15)
.width('100%')
.onClick(() => {
// 跳转到 "我的收藏" 页面
router.pushUrl({ url: 'view/mylove' });
})
// --- 主要修改点:收货地址 ---
Row() {
Text('收货地址')
.fontSize(14)
.flexGrow(1) // 让文字占据左侧空间
}
.padding(15)
.width('100%')
.onClick(() => {
// 跳转到 "我的地址" 页面
router.pushUrl({ url: 'view/myaddress' });
})
}
.backgroundColor('#ffffff')
.margin({ top: 10 })
.width('100%')
// 弹性拉伸,将按钮推到底部
// 4. 退出登录按钮
Button('退出登录')
.width('90%')
.height(40)
.backgroundColor('#e5e8ea')
.fontColor('#000000')
.margin({ bottom: 30 })
.onClick(() => {
router.pushUrl({ url: 'pages/LoginPage' });
})
}
.backgroundColor('#f5f5f5')
.width('100%')
.height('100%')
}
}
更多推荐


所有评论(0)