实战案例——黑马健康(5)

前言

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

一、项目介绍

黑马健康App是一款功能全面的健康管理应用,黑马健康App通过提供个性化的饮食记录、健康评估等功能,帮助用户轻松管理健康,改善饮食和生活习惯。 还提供个性化的推荐服务,确保用户能够获得最适合自己的健康和运动建议。总的来说,黑马健康App是一款功能全面、注重个性化推荐的健康管理应用,旨在为用户提供一站式的健康和运动解决方案。

二、具体页面实现

1.一次开发多端部署

(1)页面分析

多设备响应式布局,通过不同设备的屏幕大小来进行自定义样式布局。

(2)代码

//媒体查询工具类
import mediaQuery from '@ohos.mediaquery'
import BreakpointConstants from '../constants/BreakpointConstants'

export default class BreakpointSystem{

  //监听器(小屏幕中屏幕大屏幕)(ets文件导入BreakpointConstants)
  //监听器分别设置不同的查询条件
  private smListener: mediaQuery.MediaQueryListener = mediaQuery.matchMediaSync(BreakpointConstants.RANGE_SM)
  private mdListener: mediaQuery.MediaQueryListener = mediaQuery.matchMediaSync(BreakpointConstants.RANGE_MD)
  private lgListener: mediaQuery.MediaQueryListener = mediaQuery.matchMediaSync(BreakpointConstants.RANGE_LG)

  //回调函数,什么屏幕存什么标记
  smListenerCallback(result: mediaQuery.MediaQueryResult){
    if(result.matches){//匹配则存储
      //调用updateCurrentBreakpoint函数,传标记
      this.updateCurrentBreakpoint(BreakpointConstants.BREAKPOINT_SM)
    }
  }

  mdListenerCallback(result: mediaQuery.MediaQueryResult){
    if(result.matches){
      this.updateCurrentBreakpoint(BreakpointConstants.BREAKPOINT_MD)
    }
  }

  lgListenerCallback(result: mediaQuery.MediaQueryResult){
    if(result.matches){
      this.updateCurrentBreakpoint(BreakpointConstants.BREAKPOINT_LG)
    }
  }

  //
  updateCurrentBreakpoint(breakpoint: string){
    //currentBreakpoint设置为全局变量,值为传入的标记
    AppStorage.SetOrCreate(BreakpointConstants.CURRENT_BREAKPOINT, breakpoint)
  }

  //注册
  register(){
    this.smListener.on('change', this.smListenerCallback.bind(this))
    this.mdListener.on('change', this.mdListenerCallback.bind(this))
    this.lgListener.on('change', this.lgListenerCallback.bind(this))
  }

  //取消注册
  unregister(){
    this.smListener.off('change', this.smListenerCallback.bind(this))
    this.mdListener.off('change', this.mdListenerCallback.bind(this))
    this.lgListener.off('change', this.lgListenerCallback.bind(this))
  }
}
declare interface BreakpointTypeOptions<T>{
  //类型不确定(泛型)
  sm?:T,
  md?:T,
  lg?:T
}

export default class BreakpointType<T>{
  options: BreakpointTypeOptions<T>

  constructor(options: BreakpointTypeOptions<T>) {
    this.options = options
  }

  getValue(breakpoint: string): T{
    return this.options[breakpoint]
  }
}
//首页
import BreakpointType from '../common/bean/BreanpointType'
import BreakpointConstants from '../common/constants/BreakpointConstants'
import { CommonConstants } from '../common/constants/CommonConstants'
import BreakpointSystem from '../common/utils/BreakpointSystem'
import RecordIndex from '../view/record/RecordIndex'
@Entry
@Component
struct Index {
  //状态变量,默认为0
  @State currentIndex: number = 0

  //
  private breakpointSystem:BreakpointSystem=new BreakpointSystem()
  @StorageProp('currentBreakpoint') currentBreakpoint:string=BreakpointConstants.BREAKPOINT_SM//只读且初始化为小屏幕

  //自定义bar(参数:导航栏题目,图片,序号)
  @Builder TabBarBuilder(title:ResourceStr, image:ResourceStr, index:number){
    Column({space:CommonConstants.SPACE_8}){
      Image(image)
        .width(22)
        .fillColor(this.selectColor(index))
      Text(title)
        .fontSize(14)
        .fontColor(this.selectColor(index))
    }
  }

  //生命周期函数
  aboutToAppear(){
    this.breakpointSystem.register()
  }
  aboutToDisappear(){
    this.breakpointSystem.unregister()
  }

  //底部导航栏颜色
  selectColor(index:number){
    //状态变量与序号相同则变为主题色,不同则是灰的
    return this.currentIndex===index?$r('app.color.primary_color'):$r('app.color.gray')
  }

  // chooseBarPosition(){
  //   return new BreakpointType({
  //     sm:BarPosition.End,
  //     md:BarPosition.Start,
  //     lg:BarPosition.Start,
  //   }).getValue(this.currentBreakpoint)
  // }

  build() {
    Tabs({barPosition: BreakpointConstants.BAR_POSITION.getValue(this.currentBreakpoint)}) {//导航栏底部
      TabContent(){
        RecordIndex()//调用饮食记录页面
      }
      .tabBar(this.TabBarBuilder($r('app.string.tab_record'), $r('app.media.ic_calendar'), 0))

      TabContent(){
        Text('发现页面')
      }
      .tabBar(this.TabBarBuilder($r('app.string.tab_discover'), $r('app.media.discover'), 1))

      TabContent(){
        Text('我的主页')
      }
      .tabBar(this.TabBarBuilder($r('app.string.tab_user'), $r('app.media.ic_user_portrait'), 2))

    }
    .width('100%')
    .height('100%')
    .onChange(index=>this.currentIndex=index)//状态变量获取目前页面的序号
    .vertical(new BreakpointType({
      sm:false,
      md:true,
      lg:true
    }).getValue(this.currentBreakpoint))//
  }
}
//统计卡片(饮食记录页面)
import BreakpointType from '../../common/bean/BreanpointType'
import BreakpointConstants from '../../common/constants/BreakpointConstants'
import { CommonConstants } from '../../common/constants/CommonConstants'
import DateUtil from '../../common/utils/DateUtil'
import CalorieStats from './CalorieStats'
import DatePickDialog from './DatePickDialog'
import NutrientStats from './NutrientStats'


@Component
export default struct StatsCard {
  //单向绑定prop,读取selectedDate(number类型且没有精确到时分秒)
  @StorageProp('selectedDate') selectedDate:number=DateUtil.beginTimeOfDay(new Date())

  @StorageProp('currentBreakpoint') currentBreakpoint:string=BreakpointConstants.BREAKPOINT_SM//只读且初始化为小屏幕

  controller:CustomDialogController=new CustomDialogController({
    builder:DatePickDialog({selectedDate:new Date(this.selectedDate)})//下次打开传入
  })

  build() {
    Column(){
      //1.日期信息
      Row(){
        Text(DateUtil.formatDate(this.selectedDate))
          .fontColor($r('app.color.secondary_color'))
        Image($r('app.media.ic_public_spinner'))
          .width(20)
          .fillColor($r('app.color.secondary_color'))
      }
      .padding(CommonConstants.SPACE_8)
      .onClick(()=>this.controller.open())//打开弹窗

      //2.统计信息
      Swiper(){//滑动轮播
        //2.1.热量统计
        CalorieStats()
        //2.2.营养素统计
        NutrientStats()
      }
      .width('100%')
      .backgroundColor(Color.White)
      .borderRadius(CommonConstants.DEFAULT_18)
      .indicatorStyle({selectedColor:$r('app.color.primary_color')})//穿梭框样式,被选中后的颜色
      .displayCount(new BreakpointType({
        sm:1,
        md:1,
        lg:2
      }).getValue(this.currentBreakpoint))
    }
    .width(CommonConstants.THOUSANDTH_940)
    .backgroundColor($r('app.color.stats_title_bgc'))
    .borderRadius(CommonConstants.DEFAULT_18)
  }
}

(3)运行结果

总结

通过本视频的学习,我学会了如何进行多设备响应式布局,即在不同的设备上的样式等也会随之响应发生变化。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下为B站黑马JavaScript的Ajax案例代码——图书管理案例搜索事件: ```javascript /** * 搜索事件 */ function searchBook() { // 获取搜索框内容 var searchInput = document.querySelector("#searchInput"); var keywords = searchInput.value.trim(); // 如果搜索框内容为空,提示用户 if (keywords == "") { alert("请输入关键字进行搜索!"); return; } // 发送Ajax请求 var xhr = new XMLHttpRequest(); // 创建XmlHttpRequest对象 xhr.open("GET", "/api/book/search?keywords=" + keywords, true); // 配置请求 xhr.onreadystatechange = function () { if (xhr.readyState == 4 && xhr.status == 200) { // 处理响应数据 var books = JSON.parse(xhr.responseText); // 将响应数据转成JavaScript对象 renderBooks(books); // 渲染图书列表 } }; xhr.send(null); // 发送请求 } /** * 渲染图书列表 * @param {*} books 图书列表数据 */ function renderBooks(books) { // 获取图书列表容器 var bookList = document.querySelector("#bookList"); var html = ""; if (books.length > 0) { // 遍历图书列表数据,生成HTML字符串 for (var i = 0; i < books.length; i++) { html += '<tr>'; html += '<td>' + books[i].title + '</td>'; html += '<td>' + books[i].author + '</td>'; html += '<td>' + books[i].category + '</td>'; html += '<td>' + books[i].price + '</td>'; html += '<td>' + books[i].publisher + '</td>'; html += '</tr>'; } } else { // 如果没有搜索到任何图书,提示用户 html = '<tr><td colspan="5">没有搜索到任何图书!</td></tr>'; } // 将生成的HTML字符串添加进图书列表容器 bookList.innerHTML = html; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值