前言
这个页面主要是布局,和数据的传递,当然不是标准
UI
1.整体布局为Stack布局,因为底部的那一栏始终要展示在最上面。
2.确定好了布局之后,第一层是商品列表,第二层我做了一个像美团外卖那样的像弹窗,点击底部金额可以调出,点击已选择的商品外的区域或者底部金额就可以让它回去
3.对于商品卡片和已经购买的商品卡片都选择定义组件,列表都选择List组件
4.使用Text和Spen组件配合使部分文字个性化(不太明显,就是货币单位)
JS
1.声明一个Good类为商品类型
2.做了一个假的数据库goods,考虑到子组件也要对【已经购买的商品】列表进行操作,所以将【已经购买的商品】列表声明在全局
3.数组只有删除和新增,都是使用了数组的基本方法push和splice
4.数据传递方面,对于总金额使用了Link,对于Good类加上来Observed,对于其实例加上了ObjectLink,这个是为了数据的双向同步
功能
1.可以在商品列表中将商品加入至购物车
2.点击金额后可以查看【已经购买的商品】列表以及金额
3.在商品列表中将数量减为0后,从【已经购买的商品】列表中移除
BUG
本来有一个bug,index索引来删除【已经购买商品列表】的问题,索引会冲突,所以我用filter用name属性值来过滤掉,然后重新复制给【已经购买的商品列表】。
所有的代码其实都可以分成很多个模块,然后在主页面中进行引入,这样更具有规范性
效果
代码
import { curves } from '@kit.ArkUI';
@Observed
class Good{
//名称
name:string
//存货数量
leftNum:number
//已卖出多少
soldNum:number
//用户已选择多少
selectedNum:number
//价格
price:number
//折扣
discount:number
//图片
pictureSrc:Resource
constructor(name:string,leftNum:number,soldNum:number,selectedNum:number,price:number,discount:number,pictureSrc:Resource) {
this.name = name
this.leftNum = leftNum
this.soldNum = soldNum
this.selectedNum = selectedNum
this.price = price
this.discount = discount
this.pictureSrc = pictureSrc
}
}
let selectedGoods:Good[] = []
@Entry
@Component
struct TakeOutPage {
@State message: string = 'Hello World';
@State isShow: boolean = false
@State index: number = 20
//商品列表数据库
@State goods:Good[] = [
new Good('珍珠奶茶',10,20,0,7.0,0.95,$r('app.media.head')),
new Good('泷珠奶茶',10,20,0,7.0,0.95,$r('app.media.head')),
new Good('薄荷奶绿',10,20,0,7.0,0.95,$r('app.media.head')),
new Good('桃桃乌龙',10,20,0,7.0,0.95,$r('app.media.head')),
new Good('杨枝甘露',10,20,0,7.0,0.95,$r('app.media.head')),
new Good('柠檬茶',10,20,0,7.0,0.95,$r('app.media.head')),
new Good('百香果',10,20,0,7.0,0.95,$r('app.media.head')),
new Good('草莓啵啵',10,20,0,7.0,0.95,$r('app.media.head')),
new Good('柠檬红茶',10,20,0,7.0,0.95,$r('app.media.head')),
new Good('柠檬绿茶',10,20,0,7.0,0.95,$r('app.media.head')),
new Good('三拼霸霸奶茶',10,20,0,9.0,0.95,$r('app.media.head')),
new Good('椰果奶茶',10,20,0,9.0,0.95,$r('app.media.head')),
new Good('芋圆奶茶',10,20,0,9.0,0.95,$r('app.media.head')),
new Good('布丁奶茶(大杯)',10,20,0,9.0,0.95,$r('app.media.head')),
new Good('茉莉奶茶',10,20,0,5.0,0.95,$r('app.media.head')),
]
@State spend:number = 0
//生成数据库-已经选好的商品
private effect:TransitionEffect =
TransitionEffect.translate({y:150}).animation({curve:curves.springMotion()})
.combine(TransitionEffect.move(TransitionEdge.BOTTOM))
build() {
Column() {
Stack({
alignContent: Alignment.Bottom
})
{
//商品列表
List() {
ForEach(this.goods,(item:Good,index)=>{
ListItem(){
GoodItem({good:item,index:index,spend:this.spend})
}
})
ListItem(){
Text('到底了···')
.fontSize(40)
.height(100)
}
.width('90%')
}
.width('100%')
.height('100%')
//底部外卖栏
Row() {
Text('外卖logo')
.width('20%')
.height('100%')
.backgroundColor(Color.Yellow)
.borderRadius({ topLeft: 10 })
Text(`${this.spend.toFixed(2)}元`)
.layoutWeight(1)
.backgroundColor(Color.Gray)
.textAlign(TextAlign.Center)
.height('100%')
.onClick(() => {
// 点击弹出已选择的商品列表页面
this.isShow = !this.isShow
})
Text('选好了')
.width('25%')
.backgroundColor(Color.Orange)
.height('100%')
.borderRadius({ topRight: 10 })
.onClick(() => {
// 点击去结算页面
})
}
.width('95%')
.height('10%')
.zIndex(999)
//点击底部外卖栏后弹出已经购买的商品列表
if (this.isShow) {
Column() {
Row()
.width('100%')
.layoutWeight(1)
.onClick(() => {
this.isShow = false
})
.backgroundColor(Color.Gray)
.opacity(0.5)
Column() {
List({space:6}) {
ForEach(selectedGoods,(item:Good,index)=>{
ListItem() {
//已经购买的商品
SelectedGoodItem({selectedGoodItem:item})
}.width('90%')
.borderRadius(10)
})
}
.alignListItem(ListItemAlign.Center)
.height('50%')
}
.transition(this.effect)
.backgroundColor(Color.White)
}
.width('100%')
.height('100%')
.zIndex(this.index)
}
}
.height('100%')
}
.height('100%')
.width('100%')
}
}
//设置自定义的商品卡片组件
@Component
struct GoodItem {
//判断是否购买了
index:number = -1
@ObjectLink good:Good
@Link spend:number
sum(){
this.spend = selectedGoods.reduce((accumulator:number,item:Good)=>{
return accumulator+(item.selectedNum*item.price)
},0)
}
build() {
Row(){
//picture
Image(this.good.pictureSrc)
.width(200)
//goodInfo
Column({space:20}){
//名称
Text(this.good.name)
.fontSize(20)
.fontWeight(FontWeight.Bold)
//已售数量
Text(`已售${this.good.soldNum}`)
//价格+购买按钮
Row(){
Text(){
Span('¥')
.fontSize(14)
Span(`${this.good.price}`)
.fontSize(20)
}
.width(35)
.layoutWeight(1)
//购买按钮
if (this.good.selectedNum>0){
//- 数量 +
Row({space:3}){
Button('-')
.onClick(() => {
this.good.selectedNum--
if(this.good.selectedNum==0){
selectedGoods = selectedGoods.filter(selectedGood=>selectedGood.name!==this.good.name)
}
this.sum()
})
Text(`${this.good.selectedNum}`)
.width(20)
.textAlign(TextAlign.Center)
if (this.good.selectedNum == this.good.leftNum) {
Button('+',{stateEffect:false})
.backgroundColor('#ccc')
}else{
Button('+')
.onClick(() => {
this.good.selectedNum++
this.sum()
})
}
}
}else {
Button('购买')
.backgroundColor(Color.Orange)
.onClick(() => {
selectedGoods.push(this.good)
this.good.selectedNum++
this.sum()
})
}
}
.width('45%')
.justifyContent(FlexAlign.SpaceAround)
}
}
.justifyContent(FlexAlign.SpaceAround)
.width('95%')
.padding(3)
}
}
//自定义已经购买的组件
@Component
struct SelectedGoodItem {
@ObjectLink selectedGoodItem:Good
build() {
Row({space:5}){
//图片
Image(this.selectedGoodItem.pictureSrc)
.width('50%')
// price
Column({space:10}){
Text(`${this.selectedGoodItem.name}`)
.width('100%')
.fontSize(20)
.fontWeight(400)
Text(`数量:${this.selectedGoodItem.selectedNum}`)
.width('100%')
Text(`金额:${this.selectedGoodItem.selectedNum*this.selectedGoodItem.price}元`)
.width('100%')
}
.alignItems(HorizontalAlign.Center)
.width('50%')
}
.width('100%')
.height(80)
}
}
这个是自己手搓的,就是丑了点