记录:鸿蒙实战案例(源于黑马程序员视频)

学习内容:

观看黑马程序员视频完成实现数据持久化和页面交互


学习时间:

2024年6月22日


学习产出:

一.日期查询,并将其运用到各组件

1.在RecordIndex中加入以下代码:

默认日期为今天

当用户选择日期后 调用RecordService.queryRecordByDate,进行查询,结果为records

 监控日期变更运用@Watch('aboutToAppear'),日期变更,触发aboutToAppear函数,会进行查询

 @StorageProp('selectedDate')
  //监控日期变更
  @Watch('aboutToAppear')
  selectedDate:number = DateUtil.beginTimeOfDay(new Date())
  @Provide records:RecordVO[]=[]

  async aboutToAppear(){
    this.records=await RecordService.queryRecordByDate(this.selectedDate)
  }

 2.在StatsCard中使用所得到的records,并将其转换为StatsInfo,直接进行渲染

 @Consume @Watch('handleRecordsChange') records:RecordVO[]
  @State info:StatsInfo=new StatsInfo()

 //处理records变更,把records的数据重新运算构造StatsInfo()
  handleRecordsChange(){
    this.info=RecordService.calculateStatsInfo(this.records)
  }

(1) CalorieStats中

  @Prop intake:number
  @Prop expand:number

 (2) NutrientStats中

  @Prop carbon:number
  @Prop protein:number
  @Prop fat:number

在StatsCard中对 CalorieStats,NutrientStats进行渲染

Swiper() {
        //2.1热量统计
        CalorieStats({intake:this.info.intake,expand:this.info.expend})
        //2.2营养素统计
        NutrientStats({carbon:this.info.carbon,protein:this.info.protein,fat:this.info.fat})


      }

3.在RecordList中使用所得到的records,并将其转换为GroupInfo

  @Consume @Watch('handleRecordsChange') records:RecordVO[]
  @State groups:GroupInfo<RecordType,RecordVO>[]=[]

  //处理records变更,把records的数据重新运算构造StatsInfo()
  handleRecordsChange(){
    this.groups=RecordService.calculateGroupInfo(this.records)
  }

直接进行渲染

  build() {
    List({space:CommonConstants.SPACE_10}){
      ForEach(this.groups,(group:GroupInfo<RecordType,RecordVO>)=>{
        ListItem(){
          Column(){
            //1、分组的标题
            Row({space:CommonConstants.SPACE_4}){
              Image(group.type.icon).width(24)
              Text(group.type.name).fontSize(18).fontWeight(CommonConstants.FONT_WEIGHT_700)
              Text(`建议${group.type.min}-${group.type.max}千卡`).grayText()
              Blank()
              Text(group.calorie.toFixed(0)).fontSize(14).fontColor($r('app.color.primary_color'))
              Text('千卡').grayText()
              Image($r('app.media.ic_public_add_norm_filled'))
                .width(20)
                .fillColor($r('app.color.primary_color'))

            }
            .width('100%')
            //2.组内记录列表
            List(){
              ForEach(group.items,(item:RecordVO)=>{
                ListItem(){
                  Row({space:CommonConstants.SPACE_6}){
                    Image(item.recordItem.image).width(50)
                    Column({space:CommonConstants.SPACE_4}){
                      Text(item.recordItem.name).fontWeight(CommonConstants.FONT_WEIGHT_500)
                      Text(`${item.amount}${item.recordItem.unit}`).grayText()
                    }
                    Blank()
                    Text(`${item.calorie}千卡`).grayText()
                  }
                  .width('100%')
                  .padding(CommonConstants.SPACE_6)

                }.swipeAction({end:this.deleteButton.bind(this)})
              })
            }
            .width('100%')
          }
          .width('100%')
          .backgroundColor(Color.White)
          .borderRadius(CommonConstants.DEFAULT_18)
          .padding(CommonConstants.SPACE_12)
        }
      })
    }
    .width(CommonConstants.THOUSANDTH_940)
    .margin({top:10})
    .height('100%')
  }

二.点击分组标题跳转到对应的饮食列表页面

1.在 RecordList目录下的分组标题部分添加点击事件

.onClick(()=>{
              router.pushUrl({
                url:'pages/ItemIndexPage',
                params:{type:group.type}
              })
            })

 2.在ItemIndexPage,获取类型并判断是否是食物

  onPageShow(){
    //1.获取跳转时的参数
    let params:any=router.getParams()
    //2.获取点击的饮食记录类型
    this.type = params.type
    this.isFood=this.type.id!==RecordTypeEnum.WORKOUT
  }

三.持久化保存

点击面板的提交按钮后,会进行持久化保存,调用RecordService.insert

.onClick(()=>{
              //1.持久化保存
              RecordService.insert(this.type.id,this.item.id,this.amount)
                .then(()=>{
                  //2.关闭弹窗
                  this.showPanel=false

                })

            })

问题:

1.运行到模拟器上点击提交后没有显示记录

原因:页面跳转添加新的信息后,再次回到此页面,aboutToAppear()不会重复创建,不会重新查询

async aboutToAppear(){
    this.records=await RecordService.queryRecordByDate(this.selectedDate)
  }

 解决方法:由于RecordIndex是个组件,没有onPageShow函数,只能通过首页Index来通知RecordIndex,

在Index中定义状态变量

@State isPageShow:boolean = false

  //页面显示
  onPageShow(){
    this.isPageShow=true
  }
  //页面隐藏
  onPageHide(){
    this.isPageShow=false
  }

 在RecordIndex中使用和监测状态变量

  @Prop @Watch('handelPageShow') isPageShow:boolean

  //isPageShow为true时进行查询
  handelPageShow(){
    if(this.isPageShow){
      this.aboutToAppear()
    }

  }

2.

散步的数据出现问题

将RecordList 中组内记录列表的热量进行取整

Text(`${item.calorie.toFixed(0)}千卡`).grayText()

3. 饮食摄入和运动消耗以及后面的摄入推荐都为0:

CalorieStats, NutrientStats 中Builder函数没有触发视图更新,

Builder函数特性:默认情况下参数只是值,不是引用,不会触发视图更新

将Builder函数改为引用
方式:$$:{label:string,value:number,tips?:string},

具体传值使用对象的形式,

将CalorieStats改为如下形式:

import { CommonConstants } from '../../common/constants/CommonConstants'

@Component
export default struct CalorieStats {
  @Prop intake:number
  @Prop expand:number
  recommend:number=CommonConstants.RECOMMEND_CALORIE

  remainCalorie(){
    return this.recommend-this.intake+this.expand
  }
  build() {
    Row({ space: CommonConstants.SPACE_6 }) {
      //1.饮食摄入
      this.StatsBuilder({ label:'饮食摄入', value:this.intake })
      //2.还可以吃
      Stack(){
        //2.1进度条
        Progress({
          value:this.intake,
          total:this.recommend,
          type:ProgressType.Ring
        })
          .width(120)
          .style({strokeWidth:CommonConstants.DEFAULT_10})
          .color($r('app.color.primary_color'))
        //2.2统计数据
        this.StatsBuilder({label:'还可以吃',value:this.remainCalorie(),tips:`推荐${this.recommend}`})
      }

      //3.运动消耗
      this.StatsBuilder({ label:'运动消耗', value:this.expand })


    }
    .width('100%')
    .justifyContent(FlexAlign.SpaceEvenly)
    .padding({top:30,bottom:35})

  }
  @Builder StatsBuilder($$:{label:string,value:number,tips?:string}){
    Column({ space: CommonConstants.SPACE_6 }) {
      Text($$.label)
        .fontColor($r('app.color.gray'))
        .fontWeight(CommonConstants.FONT_WEIGHT_600)
      Text($$.value.toFixed(0))
        .fontSize(20)
        .fontWeight(CommonConstants.FONT_WEIGHT_700)
      if($$.tips){
        Text($$.tips)
          .fontSize(12)
          .fontColor($r('app.color.light_gray'))
      }

    }
  }

}

4.当进入面板点击完一个食物时,再次点击其他食物,热量会变为与第一个相同

 

解决方法:

在ItemCard中同样修改Builder函数

  @Builder NutrientInfo($$:{label:string,value:number}){
    Column({space:CommonConstants.SPACE_8}){
      Text($$.label).fontSize(14).fontColor($r('app.color.light_gray'))
      //转为小数位数为一位的小数
      Text(($$.value*this.amount).toFixed(1)).fontSize(18).fontWeight(CommonConstants.FONT_WEIGHT_700)
    }
  }

5.发现每次点击时总会出现有的文本变小 

  • 32
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值