期末项目黑马健康3

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

综合运用本学期所学内容及个人自学知识,使用HarmonyOS 4.0 及以上版本开发一款具有实用性和创新性的移动应用软件。


一、项目名称:黑马健康运动

黑马健康是一款流行的运动健身软件,旨在帮助用户保持健康和锻炼,致力于提供健身教学、跑步、骑行、交友及健身饮食指导一站式运动解决方案。健身、跑步、骑行,运动品类更丰富,个性化推荐更加精细。

二、应用运行过程3

1.食物列表页

1.1. 分析列表页面结构:从上到下列式布局,第一部分第一行是一个导航条,左侧是一个返回按钮,右侧是一个文本,第二部分是Tabs
当用户点击饮食记录页面某一个分组时,跳转到食物列表页面,创建一个新页面ItemIndex
1.2 头部导航 行式布局,封装到Builder
1.3 列表,创建一个组件,view/item/ItemList

运行截图:
在这里插入图片描述

代码如下(示例):

import router from '@ohos.router'
import { CommonConstants } from '../common/constants/CommonConstants'
import { RecordTypeEnum, RecordTypes } from '../model/RecordTypeModel'
import RecordService from '../service/RecordService'
import ItemCard from '../view/item/ItemCard'
import ItemList from '../view/item/ItemList'
import ItemPanelHeader from '../view/item/ItemPanelHeader'
import NUmberKeyboard from '../view/item/NumberKeyboard'
import RecordItem from '../viewmodel/RecordItem'
import RecordType from '../viewmodel/RecordType'
@Entry
@Component
struct ItemIndex {
  @State amount:number = 1
  @State value: string = ''//按键记录
  @State showPanel: boolean = false
  @State item: RecordItem = null
  @State type: RecordType = RecordTypes[0]
  @State isFood: boolean = true

  onPanelShow(item: RecordItem){//定义函数,当panel要展示时做一些事情
    this.amount = 1
    this.value = ''
    this.item = item
    this.showPanel = true//控制弹窗展示
  }

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

  build() {
    Column() {
      //1.头部导航
      this.Header()
      //2.列表
      ItemList({showPanel: this.onPanelShow.bind(this), isFood: this.isFood})
      .layoutWeight(1)
      //3.底部面板
      Panel(this.showPanel) { //使用时需要传入一个布尔类型的参数
        //3.1.顶部日期
        ItemPanelHeader()
        //3.2.记录项卡片
        if (this.item) {
          ItemCard({ amount: this.amount, item: $item })
        }
        //3.3.数字键盘
        NUmberKeyboard({ amount: $amount, value: $value })
        //3.4.按钮
        this.PanelButton()
      }
      .mode(PanelMode.Full)
      .dragBar(false)
      .backgroundMask($r('app.color.light_gray'))
      .backgroundColor(Color.White)
    }
    .width('100%')
    .height('100%')
  }

  @Builder PanelButton(){
    Row({space:CommonConstants.SPACE_6}){
      Button('取消')
        .width(120)
        .backgroundColor($r('app.color.light_gray'))
        .type(ButtonType.Normal)//样式
        .borderRadius(6)//边角
        .onClick(() => this.showPanel = false)
      Button('提交')
        .width(120)
        .backgroundColor($r('app.color.primary_color'))
        .type(ButtonType.Normal)//样式
        .borderRadius(6)//边角
        .onClick(() => {
          //1.持久化保存
          RecordService.insert(this.type.id, this.item.id, this.amount)
            .then(() => {
              //2.关闭弹窗
              this.showPanel = false
            })
        })
    }
    .margin({top: 10})
  }

  @Builder Header(){
    Row(){
      Image($r('app.media.ic_public_back'))
        .width(24)
        .onClick(() => router.back())//点击事件 返回
      Blank()
      Text(this.type.name).fontSize(18).fontWeight(CommonConstants.FONT_WEIGHT_600)
    }
    .width(CommonConstants.THOUSANDTH_940)
    .height(32)
  }
}

2.食物列表—底部Panel

底部弹出面板,列式布局,去食物列表页设置点击事件,当点击时弹出来
2.1.顶部日期,新建组件view/item/ItemPanelHeader
文本内容Text(‘2024年1月25日 早晨’),居中
2.2记录项卡片,新建组件view/item/ItemCard
首先为图片信息(先写固定);然后名称信息 食物名称:Text(‘全麦吐司’)
下划线:Divider()
再 营养素信息NutrientInfo(需要传参)定义在Builder:label,value(数值)
最后 食物或运动数量:定义一个状态变量@Prop amount(用prop接收)

运行截图:
在这里插入图片描述

代码如下(示例):
itemPanelHeader.ets

import { CommonConstants } from '../../common/constants/CommonConstants'
@Component
export default struct ItemPanelHeader {
  build() {
    Row(){
      Text('2024125日 早餐')
        .fontSize(18).fontWeight(CommonConstants.FONT_WEIGHT_600)
      Image($r('app.media.ic_public_spinner'))
        .width(20)
        .fillColor(Color.Black)
    }
    .width(CommonConstants.THOUSANDTH_940)
  }
}

itemCard.ets

import { CommonConstants } from '../../common/constants/CommonConstants'
import RecordItem from '../../viewmodel/RecordItem'
@Component
export default struct ItemCard {

  @Prop amount:number//用Prop接收,和键盘不在一个组件中
  @Link item: RecordItem

  build() {
    Column({space:CommonConstants.SPACE_8}){
      //1.图片信息
      Image(this.item.image).width(150)
      //2.名称
      Row(){
        Text(this.item.name).fontWeight(CommonConstants.FONT_WEIGHT_700)
      }
      .backgroundColor($r('app.color.lightest_primary_color'))
      .padding({top: 5, bottom: 5, left:12, right: 12})
      Divider().width(CommonConstants.THOUSANDTH_940).opacity(0.6)//下划线
      //3.营养素信息
      Row({space:CommonConstants.SPACE_8}){
        this.NutrientInfo({label: '热量(千卡)', value: this.item.calorie})
        if (this.item.id < 10000){
          this.NutrientInfo({label: '碳水(克)', value: this.item.carbon})
          this.NutrientInfo({label: '蛋白质(克)', value: this.item.protein})
          this.NutrientInfo({label: '脂肪(克)', value: this.item.fat})
        }
      }
      Divider().width(CommonConstants.THOUSANDTH_940).opacity(0.6)//下划线
      //4.数量信息
      Row(){
        Column({space:CommonConstants.SPACE_4}){
          Text(this.amount.toFixed(1)).fontSize(50).fontColor($r('app.color.primary_color'))
            .fontWeight(CommonConstants.FONT_WEIGHT_600)
          Divider().color($r('app.color.primary_color'))
        }
        .width(150)
        Text(this.item.unit)
          .fontColor($r('app.color.light_gray'))
          .fontWeight(CommonConstants.FONT_WEIGHT_600)
      }
    }
  }

  @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)
    }
  }
}

3.食物列表—数字键盘

view/item/NumberKeyboard

Grid组件:容器型组件,网格容器,由行和列分割的单元格所组成,通过指定“项目”所在的单元格做出各种各样的布局。

接口 Grid(scroller ?: Scroller)

定义value记录用户输入数字,增加点击事件:点击数字,拼接用户输入的内容;校验输入格式是否正确:小数点数量不能超过两个,小数不能超过两位;将字符串转为数值(有上限);保存
运行截图:
在这里插入图片描述
代码如下:

import { CommonConstants } from '../../common/constants/CommonConstants'
@Component
export default struct NUmberKeyboard {
  
  numbers: string [] = ['1', '2', '3', '4','5', '6', '7', '8', '9','0', '.']

  @Link amount: number//双向,修改amount的值
  @Link value: string

  @Styles keyBoxStyle(){
    .backgroundColor(Color.White)
    .height(60)
    .borderRadius(8)
  }

  build() {
    Grid(){
      ForEach(this.numbers, num => {
        GridItem(){
          Text(num).fontSize(20).fontWeight(CommonConstants.FONT_WEIGHT_900)
        }
        .keyBoxStyle()
        .onClick(() => this.clickNumber(num))
      })
      GridItem(){
        Text('删除').fontSize(20).fontWeight(CommonConstants.FONT_WEIGHT_900)
      }
      .keyBoxStyle()
      .onClick(() => this.clickDelete())
    }
    .width('100%')
    .height(280)
    .backgroundColor($r('app.color.index_page_background'))
    .columnsTemplate('1fr 1fr 1fr')
    .columnsGap(8)//列间距
    .rowsGap(8)//行间距
    .padding(8)//内边距
    .margin({top:10})//外边距
  }

  clickNumber(num: string){
    //1.拼接用户输入的内容
    let val = this.value + num//拼接
    //2.校验输入格式是否正确
    let firstIndex = val.indexOf('.')
    let lastIndex = val.lastIndexOf('.')
    if(firstIndex !== lastIndex || (lastIndex != -1 && lastIndex < val.length -2)){
      //非法输入
      return
    }
    //3.将字符串转为数值
    let amount = this.parseFloat(val)
    //4.保存
    if(amount >= 999.9){
      this.amount = 999.0
      this.value = '999'
    }else{
      this.amount = amount
      this.value = val
    }
  }

  clickDelete(){//删除
    if(this.value.length <= 0){
      this.value = ''
      this.amount = 0
      return
    }
    this.value = this.value.substring(0, this.value.length - 1)
    this.amount = this.parseFloat(this.value)
  }

  parseFloat(str: string){
    if(!str){
      return 0
    }
    if(str.endsWith('.')){
      str = str.substring(0, str.length - 1)
    }
    return parseFloat(str)
  }
}

总结

1.食物列表页

分析排版
1.头部导航
2.列表
在这里插入图片描述

2.食物列表—底部Panel

在这里插入图片描述

3.食物列表—数字键盘

在这里插入图片描述

  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,我无法直接提供完整的JavaScript期末项目的源码。但是,我可以为您提供一些关于JavaScript期末项目的一般介绍和示例。 JavaScript期末项目通常要求学生设计和开发一个具有交互性和动态功能的网页。这些项目可以涉及使用HTML、CSS和JavaScript来创建各种功能,例如表单验证、动画效果、数据展示等。 以下是一个简单的JavaScript期末项目示例,用于创建一个基本的网页表单验证功能: ```html <!DOCTYPE html> <html> <head> <title>表单验证</title> <script> function validateForm() { var name = document.forms["myForm"]["name"].value; var email = document.forms["myForm"]["email"].value; if (name == "") { alert("请输入姓名"); return false; } if (email == "") { alert("请输入电子邮件"); return false; } } </script> </head> <body> <h1>表单验证</h1> <form name="myForm" onsubmit="return validateForm()"> <label for="name">姓名:</label> <input type="text" id="name" name="name"><br><br> <label for="email">电子邮件:</label> <input type="email" id="email" name="email"><br><br> <input type="submit" value="提交"> </form> </body> </html> ``` 在这个示例中,我们创建了一个简单的表单,要求用户输入姓名和电子邮件。然后,使用JavaScript编写了一个函数`validateForm()`来验证表单数据。如果姓名或电子邮件为空,将弹出警告框并阻止表单提交。 这只是一个简单的示例,JavaScript期末项目可以更加复杂和有创意。您可以根据自己的兴趣和要求来设计和开发一个独特的项目

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值