接上
一、UI布局
1.1 购物车Item
@Preview
@Component
export struct MTCartItemView {
build() {
Row({ space: 6 }) {
Image('https://bkimg.cdn.bcebos.com/pic/4d086e061d950a7bc94a331704d162d9f3d3c9e2')
.width(42)
.aspectRatio(1)
.borderRadius(5)
Column({ space: 3 }) {
Text('糖醋里脊+海盗虾饭')
Text() {
Span('¥')
.fontSize(10)
Span('41.99')
.fontColor($r('app.color.main_color'))
.fontSize(14)
.fontWeight(600)
}
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Start)
}
.height(60)
.alignItems(VerticalAlign.Top)
.width('100%')
.padding({ top: 12, left: 15, right: 15, bottom: 12 })
}
}
1.2 购物车
import { MTCartItemView } from './MTCartItemView'
@Preview
@Component
export struct MTCartView {
build() {
Column() {
Column() {
// 头部
Row() {
Text('购物车')
.fontSize(14)
Text('清空购物车')
.fontColor($r('app.color.search_font_color'))
.fontSize(12)
}
.width('100%')
.height(48)
.justifyContent(FlexAlign.SpaceBetween)
.padding({ left: 15, right: 15 })
// 购物车列表
List() {
ForEach([1, 2, 3, 4, 5], (item: number) => {
ListItem() {
MTCartItemView()
}
})
}
.divider({ strokeWidth: 1, color: '#e5e5e5', startMargin: 20, endMargin: 20 })
}
.backgroundColor(Color.White)
.padding({
bottom: 88
})
.borderRadius({
topLeft: 12,
topRight: 12
})
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.End)
.backgroundColor('rgba(0,0,0,0.5)')
}
}
1.3 购物车显示与隐藏
在主页面新增变量,控制是否展示购物车:
@Provide showCart: boolean = false
完整代码:
import { MTBottomView } from './components/MTBottomView'
import { MTCartView } from './components/MTCartView'
import { MTContentView } from './components/MTContentView'
import { MTTopView } from './components/MTTopView'
@Entry
@Component
struct MeiTuanPage {
@Provide showCart: boolean = false
build() {
Column() {
Stack({ alignContent: Alignment.Bottom }) {
Column() {
MTTopView()
MTContentView()
}
.width('100%')
.height('100%')
.padding({ bottom: 120 })
if (this.showCart) {
MTCartView()
}
MTBottomView()
}
}
.width('100%')
.height('100%')
.backgroundColor('#F6F6F6')
}
}
bottom
组件增加事件处理:
1.4 封装加减菜品组件
@Preview
@Component
export struct MTAddCutView {
build() {
Row({ space: 8 }) {
Row() {
Image($r('app.media.ic_screenshot_line'))
.width(10)
.aspectRatio(1)
}
.width(16)
.height(16)
.justifyContent(FlexAlign.Center)
.backgroundColor(Color.White)
.borderRadius(4)
.border({
color: $r('app.color.main_color'),
width: 0.5
})
Text('0')
.fontSize(14)
Row() {
Image($r('app.media.ic_public_add_filled'))
.width(10)
.aspectRatio(1)
}
.width(16)
.height(16)
.justifyContent(FlexAlign.Center)
.borderRadius(4)
.backgroundColor($r('app.color.main_color'))
}
}
}
在菜品Item中使用:
import { MTAddCutView } from './MTAddCutView'
@Preview
@Component
export struct MTFoodItem {
build() {
Row() {
Image('https://images.tmtpost.com/uploads/images/2022/09/c0de0f8e1051beb409d189a7283a3ccd_1664523457.jpeg?imageMogr2/auto-orient/strip/interlace/1/quality/85/thumbnail/1400x933/gravity/center/crop/!1400x933&ext=.jpeg')
.width(90)
.aspectRatio(1)
Column({ space: 5 }) {
Text('小份酸汤莜面鱼鱼+肉夹馍套餐')
.textOverflow({
overflow: TextOverflow.Ellipsis,
})
.maxLines(2)
.fontWeight(600)
Text('酸汤莜面鱼鱼,主料:酸汤、莜面 肉夹馍,主料:白皮饼、猪肉')
.textOverflow({
overflow: TextOverflow.Ellipsis,
})
.maxLines(1)
.fontSize(12)
.fontColor($r("app.color.food_item_second_color"))
Text('点评网友推荐')
.fontSize(10)
.backgroundColor($r("app.color.food_item_label_color"))
.fontColor($r("app.color.font_main_color"))
.padding({ top: 2, bottom: 2, right: 5, left: 5 })
.borderRadius(2)
Text() {
Span('月销售40')
Span(' ')
Span('好评度100%')
}
.fontSize(12)
.fontColor($r("app.color.black"))
Row() {
Text() {
Span('¥ ')
.fontColor($r("app.color.font_main_color"))
.fontSize(10)
Span('34.23')
.fontColor($r("app.color.font_main_color"))
.fontWeight(FontWeight.Bold)
}
MTAddCutView()
}
.justifyContent(FlexAlign.SpaceBetween)
.width('100%')
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Start)
.padding({ left: 10, right: 10 })
}
.padding(10)
.alignItems(VerticalAlign.Top)
.backgroundColor(Color.White)
}
}
在购物车Item中使用:
二、数据模型
2.1 定义模型
在models
下新建文件index.ets
,定义实体信息:
export class FoodItem {
id: number = 0
name: string = ""
like_ratio_desc: string = ""
food_tag_list: string[] = []
price: number = 0
picture: string = ""
description: string = ""
tag: string = ""
month_saled: number = 0
count: number = 0
}
export class Category {
tag: string = ""
name: string =""
foods: FoodItem[] = []
}
2.2 mock数据
在api
目录下新建index.ets
文件,模拟网络数据如下:
import { Category } from '../models'
export const mockCategory: Category[] = [
{
tag: "快餐简餐",
name: "中式快餐",
foods: [
{
id: 1,
name: "宫保鸡丁饭",
like_ratio_desc: "好评如潮",
food_tag_list: ["辣", "快餐"],
price: 25.0,
picture: "https://example.com/images/food1.jpg",
description: "经典川菜,鸡肉嫩滑,口味鲜美。",
tag: "热销",
month_saled: 2500,
count: 123,
},
{
id: 2,
name: "鱼香肉丝饭",
like_ratio_desc: "好评如潮",
food_tag_list: ["辣", "快餐"],
price: 28.0,
picture: "https://example.com/images/food2.jpg",
description: "经典川菜,猪肉嫩滑,口味鲜美。",
tag: "热销",
month_saled: 3000,
count: 150,
},
{
id: 3,
name: "麻婆豆腐饭",
like_ratio_desc: "好评如潮",
food_tag_list: ["辣", "快餐"],
price: 27.0,
picture: "https://example.com/images/food3.jpg",
description: "经典川菜,豆腐嫩滑,口味鲜美。",
tag: "热销",
month_saled: 3500,
count: 175,
},
{
id: 4,
name: "水煮肉片饭",
like_ratio_desc: "好评如潮",
food_tag_list: ["辣", "快餐"],
price: 30.0,
picture: "https://example.com/images/food4.jpg",
description: "经典川菜,肉片嫩滑,口味鲜美。",
tag: "热销",
month_saled: 4000,
count: 200,
},
{
id: 5,
name: "回锅肉饭",
like_ratio_desc: "好评如潮",
food_tag_list: ["辣", "快餐"],
price: 26.0,
picture: "https://example.com/images/food5.jpg",
description: "经典川菜,猪肉嫩滑,口味鲜美。",
tag: "热销",
month_saled: 2800,
count: 130,
}
],
},
{
tag: "西式料理",
name: "汉堡披萨",
foods: [
{
id: 2,
name: "牛肉汉堡",
like_ratio_desc: "多数好评",
food_tag_list: ["西式", "快餐"],
price: 30.0,
picture: "https://example.com/images/food2.jpg",
description: "100%纯牛肉饼,搭配新鲜蔬菜和特制酱料。",
tag: "新品",
month_saled: 1800,
count: 98,
}, {
id: 6,
name: "意大利面",
like_ratio_desc: "多数好评",
food_tag_list: ["西式", "快餐"],
price: 25.0,
picture: "https://example.com/images/food6.jpg",
description: "经典的意大利面,配以新鲜番茄和奶酪。",
tag: "新品",
month_saled: 1500,
count: 85,
},
{
id: 7,
name: "烤鸡腿",
like_ratio_desc: "多数好评",
food_tag_list: ["西式", "快餐"],
price: 32.0,
picture: "https://example.com/images/food7.jpg",
description: "香烤的鸡肉,外皮酥脆,内部鲜嫩多汁。",
tag: "新品",
month_saled: 1600,
count: 80,
},
{
id: 8,
name: "牛排",
like_ratio_desc: "多数好评",
food_tag_list: ["西式", "快餐"],
price: 45.0,
picture: "https://example.com/images/food8.jpg",
description: "精选优质牛肉,搭配特制烧烤酱料。",
tag: "新品",
month_saled: 1400,
count: 70,
},
{
id: 9,
name: "披萨",
like_ratio_desc: "多数好评",
food_tag_list: ["西式", "快餐"],
price: 35.0,
picture: "https://example.com/images/food9.jpg",
description: "经典意式披萨,多种口味可选。",
tag: "新品",
month_saled: 1700,
count: 85,
},
{
id: 10,
name: "沙拉",
like_ratio_desc: "多数好评",
food_tag_list: ["西式", "快餐"],
price: 20.0,
picture: "https://example.com/images/food10.jpg",
description: "新鲜的蔬菜,搭配特制沙拉酱。",
tag: "新品",
month_saled: 1500,
count: 80,
}
],
},
];
三、页面数据动态获取
3.1 主页面加载数据
在MeiTuanPage.ets
文件中定义变量,存储数据,并在生命周期``中请求网络数据,如下:
@Provide categoryList: Category[] = []
aboutToAppear(): void {
setTimeout(() => {
this.categoryList = mockCategory
}, 500)
}
3.2 MTContentView渲染数据
定义变量categoryList
接收父组件的数据:
import { Category, FoodItem } from '../models'
import { MTFoodItem } from './MTFoodItem'
@Component
export struct MTContentView {
@State categoryIndex: number = 0
// 接收数据
@Consume categoryList: Category[]
build() {
if (this.categoryList && this.categoryList.length) {
Row() {
// 左侧分类
Column() {
ForEach(this.categoryList, (item: Category, index: number) => {
Text(item.name)
.height(50)
.width('100%')
.textAlign(TextAlign.Center)
.backgroundColor(this.categoryIndex === index ? Color.White : '#F6F6F6')
.onClick(() => {
this.categoryIndex = index
})
})
}
.width(100)
.backgroundColor('#F6F6F6')
.height('100%')
// 右侧食品列表
List() {
ForEach(this.categoryList[this.categoryIndex].foods, (item: FoodItem) => {
ListItem() {
// 子组件传递数据
MTFoodItem({ foodItem: item })
}
})
}
.layoutWeight(1)
.height('100%')
}
.height('100%')
.width('100%')
}
}
}
3.3 MTFoodItem渲染数据
在MTFoodItem
中渲染真实数据,如下:
import { FoodItem } from '../models'
import { MTAddCutView } from './MTAddCutView'
@Preview
@Component
export struct MTFoodItem {
foodItem: FoodItem = {} as FoodItem
build() {
if (this.foodItem && this.foodItem.name) {
Row() {
Image('https://images.tmtpost.com/uploads/images/2022/09/c0de0f8e1051beb409d189a7283a3ccd_1664523457.jpeg?imageMogr2/auto-orient/strip/interlace/1/quality/85/thumbnail/1400x933/gravity/center/crop/!1400x933&ext=.jpeg')
.width(90)
.aspectRatio(1)
Column({ space: 5 }) {
Text(this.foodItem.name)
.textOverflow({
overflow: TextOverflow.Ellipsis,
})
.maxLines(2)
.fontWeight(600)
Text(this.foodItem.description)
.textOverflow({
overflow: TextOverflow.Ellipsis,
})
.maxLines(1)
.fontSize(12)
.fontColor($r("app.color.food_item_second_color"))
Text() {
ForEach(this.foodItem.food_tag_list, (item: string) => {
Span(item + " ")
})
}
.fontSize(10)
.backgroundColor($r("app.color.food_item_label_color"))
.fontColor($r("app.color.font_main_color"))
.padding({ top: 2, bottom: 2, right: 5, left: 5 })
.borderRadius(2)
Text() {
Span(`月销售${this.foodItem.month_saled}`)
Span(' ')
Span(`${this.foodItem.like_ratio_desc}`)
}
.fontSize(12)
.fontColor($r("app.color.black"))
Row() {
Text() {
Span('¥ ')
.fontColor($r("app.color.font_main_color"))
.fontSize(10)
Span(this.foodItem.price.toString())
.fontColor($r("app.color.font_main_color"))
.fontWeight(FontWeight.Bold)
}
MTAddCutView()
}
.justifyContent(FlexAlign.SpaceBetween)
.width('100%')
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Start)
.padding({ left: 10, right: 10 })
}
.padding(10)
.alignItems(VerticalAlign.Top)
.backgroundColor(Color.White)
}
}
}
四、TODO
- 购物车、加减菜品等相关逻辑