学习内容:
观看黑马程序员视频完成实现数据持久化和页面交互
学习时间:
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.发现每次点击时总会出现有的文本变小