鸿蒙HarmonyOS全民健身项目实战完全指导

内容提要

  • 构建项目
  • 项目结构
  • 配置文件参考
  • 实体类组件
  • 模块资源文件夹
  • 自定义组件
  • 部分页面组件参考
  • 项目预览与部署

1、构建项目reservation

开发环境安装与配置参考本站:

华为鸿蒙HarmonyOS开发环境安装与配置完全解析_怎么安装配置鸿蒙环境,以次编译出jar包-CSDN博客

2、项目结构

3、配置文件参考

(1)AppScope/app.json5:全局属性配置

{
  "app": {
    "bundleName": "com.chaoke.reservation",
    "vendor": "chaoke",
    "versionCode": 1000001,
    "versionName": "1.1.0",
    "icon": "$media:icon",
    "label": "$string:app_name"
  }
}

(2)entry/src/module.json5:当前模块配置

{
  "module": {
    "name": "entry",
    "type": "entry",
    "description": "$string:module_desc",
    "mainElement": "EntryAbility",
    "deviceTypes": [
      "phone",
      "tablet"
    ],
    "deliveryWithInstall": true,
    "installationFree": false,
    "pages": "$profile:main_pages",
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ts",
        "description": "$string:EntryAbility_desc",
        "icon": "$media:icon",
        "label": "$string:EntryAbility_label",
        "startWindowIcon": "$media:icon",
        "startWindowBackground": "$color:start_window_background",
        "exported": true,
        "skills": [
          {
            "entities": [
              "entity.system.home"
            ],
            "actions": [
              "action.system.home"
            ]
          }
        ]
      }
    ]
  }
}

(3)entry/src/resources/profile/main_pages.json:页面路由设置

{
  "src": [
    "pages/Index",
    "pages/home/MyHome",
    "pages/know/MyKnow",
    "pages/message/MyMessage",
    "pages/mine/MyMine",
    "pages/restime/MyRestime",
    "pages/mine/login",
    "pages/mine/register",
    "pages/common/yuyuelist",
    "pages/restime/application",
    "pages/restime/reserdetail",
    "pages/common/detail",
    "pages/mine/reports",
    "pages/mine/update"
  ]
}

(4)/build-profile.json5:应用服务构建配置文件

{
  "app": {
    "signingConfigs": [],
    "compileSdkVersion": 9,
    "compatibleSdkVersion": 9,
    "products": [
      {
        "name": "default",
        "signingConfig": "default",
      }
    ]
  },
  "modules": [
    {
      "name": "entry",
      "srcPath": "./entry",
      "targets": [
        {
          "name": "default",
          "applyToProducts": [
            "default"
          ]
        }
      ]
    }
  ]
}

(5)hvigorfile.ts:自定义编译脚本

export { appTasks } from '@ohos/hvigor-ohos-plugin';

(6)应用的第三方依赖包,支持共享包依赖

{
  "name": "reservation",
  "version": "1.0.0",
  "description": "Please describe the basic information.",
  "main": "",
  "author": "",
  "license": "",
  "dependencies": {
  },
  "devDependencies": {
    "@ohos/hypium": "1.0.6"
  }
}

4、实体类组件

(1)User用户类

export default class User {
  username: string;
  password: string;
  mobile: string;

  constructor(username: string, password: string, mobile: string) {
    this.username = username;
    this.password = password;
    this.mobile = mobile;
  }
}

(2)Plyayer报名用户类

/**
 * 健身报名表
 */
function setState(resDate: string) {
  //用户报名时日期
  let temp1 = new Date(resDate);
  const ryear = temp1.getFullYear();
  const rmonth = temp1.getMonth();
  const rdate = temp1.getDate();
  //今天的日期
  let temp2 = new Date();
  const nyear = temp2.getFullYear();
  const nmonth = temp2.getMonth();
  const ndate = temp2.getDate();
  生成比较对象,不太准确:2024-6-29要大于2024-12-1,要分别如下比较年,月,日才行
  if (ryear > nyear) { //先比较年份
    return '预约中'
  } else if (ryear == nyear) {//先比较年份
    if (rmonth > nmonth) {
      return '预约中'
    } else if (rmonth < nmonth) {
      return '已结束'
    } else {
      if (rdate > ndate) {
        return '预约中'
      } else if (rdate == ndate) {
        return '进行中'
      } else {
        return '已结束';
      }
    }

  } else {//比较年份
    return '已结束';
  }
}

export default class Player{
  //报名用户名称
  name: string;
  gender: string;
  //由手机号惟一识别用户
  mobile: string;
  //预约的场馆
  venue: string;
  //预约日期
  pdate: string
  //预约状态:进行中,已结束,已预约
  state: string = '预约中'

  constructor(name: string, gender: string, mobile: string, venue: string, pdate: string) {
    this.name = name;
    this.gender = gender;
    this.mobile = mobile;
    this.venue = venue;
    this.pdate = pdate;
    this.state = setState(pdate);
  }
}

(3) Content内容类

export default class Content {
  pic: string;
  title: string;
  info: string;
  date: string

  constructor(pic: string, title: string, info: string, date: string) {
    this.pic = pic;
    this.title = title;
    this.info = info;
    this.date = date;
  }
}

(4)Type类型类

export default class Type {
  pic: string;
  title: string;
  info: string;
  tips: string

  constructor(pic: string, title: string, info: string, tips: string) {
    this.pic = pic;
    this.title = title;
    this.info = info;
    this.tips = tips;
  }
}

5、模块资源文件夹

6、自定义组件

MyTabs.ets:预览并复用

import Home from '../pages/home/home';
import Message from '../pages/message/message';
import Know from '../pages/know/know';
import Restime from '../pages/restime/restime';
import Mine from '../pages/mine/mine';
//定义枚举,识别不同的页面
enum PAGE {
  HOME = 0,
  MESSAGE = 1,
  KNOW = 2,
  RESTIME = 3,
  MINE = 4
}

@Preview
@Component
export default struct MyTabs {
  //状态变量
  @State currentIndex: number = 0;
  //标签控制对象
  private tabsController: TabsController = new TabsController();

  //页面切换后的操作,可以做一些全局数据处理等工作
  changePage(index) { //index为选项索引号
    this.currentIndex = index;
    if (index == PAGE.HOME) { //渲染首页

    } else if (index == PAGE.MESSAGE) {
      //输出消息
      //AlertDialog.show({title:"动态",message:"你好啊"})
    } else if (index == PAGE.KNOW) {

    } else if (index == PAGE.RESTIME) {

    } else if (index == PAGE.MINE) {

    }

  }

  //自定义构建UI标签
  @Builder TabBuilder(title: string, targetIndex: number, selectedImg: Resource, normalImg: Resource) {
    Column() {
      Image(this.currentIndex == targetIndex ? selectedImg : normalImg)
        .size({ width: 22, height: 22 }).objectFit(ImageFit.Fill).margin({top:-16})
      Text(title).fontColor(this.currentIndex == targetIndex ? '#484D54' : '#ff969da9')
        .fontSize(12).margin({ top: 3, bottom: 3 })
    }
    .width('100%')
    .height(70)
    .alignItems(HorizontalAlign.Center)
    .backgroundColor('#fff')
    .justifyContent(FlexAlign.Center)
    .border({
      width: { top: 1 },
      color: { top: '#ddd' },
      style: { top: BorderStyle.Solid }
    })
    .onClick(() => {
      this.currentIndex = targetIndex;
      this.tabsController.changeIndex(targetIndex);
    })
  }

  构建UI
  build() {
    Tabs({ barPosition: BarPosition.End, controller: this.tabsController }) {
      TabContent() {
        Home(); //默认打开首页
      }.tabBar(this.TabBuilder('首页', 0, $rawfile('tabs/home_cur.png'), $rawfile('tabs/home.png')))
      .align(Alignment.Top)

      TabContent() {
        Message(); //打开动态
      }.tabBar(this.TabBuilder('场馆动态', 1, $rawfile('tabs/msg_cur.png'), $rawfile('tabs/msg.png')))
      .align(Alignment.Top)

      TabContent() {
        Know() //打开常识
      }.tabBar(this.TabBuilder('运动知识', 2, $rawfile('tabs/know_cur.png'), $rawfile('tabs/know.png')))
      .align(Alignment.Top)

      TabContent() {
        Restime() //打开预约
      }.tabBar(this.TabBuilder('场馆预约', 3, $rawfile('tabs/day_cur.png'), $rawfile('tabs/day.png')))
      .align(Alignment.Top)

      TabContent() {
        Mine() //打开我的
      }.tabBar(this.TabBuilder('我的', 4, $rawfile('tabs/my_cur.png'), $rawfile('tabs/my.png')))
      .align(Alignment.Top)
    }
    .width('100%')
    .height('100%')
    .onChange((index:number)=>{//暂未用到
      this.changePage(index);
    })
  } //build
}

7、部分页面组件参考

(1)主页入口组件Index.ets

import myTabs from '../mycomp/MyTabs';
import User from '../entity/User';
import Player from '../entity/Player';
/**
 * @Author 天涯余哥
 * @Date 2024-5-2 11:18
 * @Verson v1.0
 */
@Entry
@Component
struct Index { //项目入口
  初始化一些数据
  //用户状态数组
  @State users: Array<User> = [new User('test', '123', '13120001808')];
  //报名状态数组
  @State players: Array<Player> = [new Player('test123', '男', '13120001808', '健身馆预约', '2024-5-20')];
  //全局存取,在build之前执行完成
  aboutToAppear() {
    let utemp = AppStorage.Get<User[]>('users')
    //判断是否为首次启动
    if (utemp == null || utemp == undefined) {
      //泛型数组,全局初始化一下
      AppStorage.SetOrCreate<User[]>('users', this.users);
    }
    let ptemp = AppStorage.Get<Player[]>('players')
    if (ptemp == null || ptemp == undefined) {
      //泛型数组,全局初始化一下
      AppStorage.SetOrCreate<Player[]>('players', this.players);
    }
  }
  //构建ui
  build() {
    Column() {
      myTabs();
    }.backgroundColor("#eee")
  } //build
}

(2)common文件夹

Detail.ets组件:

import router from '@ohos.router';
import Content from '../../entity/Content';

@Entry
@Component
struct Detail {
  @State message: string = '详情'
  private msg: string = 'numquam officiis cum, quaerat ab eaque magni distinctio labore eos? Asperiores commodi velit, eveniet facilis, hic sed porro mollitia eos optio dicta quae iste ducimus nostrum cum cupiditate fugiat voluptatibus, exercitationem omnis iusto? Maiores explicabo sint error minus ipsam quasi autem aut nostrum illo possimus saepe pariatur suscipit est itaque voluptate non vel quae, qui praesentium.';
  @State obj: Content = null;
  //获取路由参数
  aboutToAppear() {
    let temp = router.getParams()['title'] as string;
    this.message = temp + this.message
    let str = router.getParams()['jsonstr'] as string;
    this.obj = JSON.parse(str); //赋给动态对象
  }
  //构建ui
  build() {
    Column() {
      1.顶部导航
      Row() {
        Text('<')
          .width('10%')
          .height('100%')
          .textAlign(TextAlign.Center)
          .fontSize(30)
          .fontWeight(FontWeight.Bold)
          .fontColor(Color.White)
          .onClick(() => { //返回
            router.back()
          })
        Text(this.message)
          .width('90%')
          .height('100%')
          .fontSize(24)
          .fontWeight(FontWeight.Bold)
          .fontColor(Color.White)
          .textAlign(TextAlign.Center)
          .padding({ right: 36 })
      }.width('100%')
      .height('12%')
      .backgroundColor('#27C189')
      2.详情内容
      Column() {
        //详情标题
        Text(this.obj.title)
          .width('100%')
          .fontSize(24)
          .fontWeight(FontWeight.Bold)
          .margin({ top: 10, bottom: 10 })
          .padding({ left: 10, right: 10 })
        Image('imgs/types/' + this.obj.pic + '.jpg').width(240).borderRadius(120)
        Text(this.obj.info+this.msg).width('100%').fontSize(18).padding(4)
      }.width('94%').height(500).backgroundColor(Color.White).height('100%')
      //------------外层column-end----------------//
    }.width('100%').height('100%').backgroundColor('#eee')
  }
}

(3)home文件夹

Home.ets组件:预览并复用

//导入公共的类,存取热门内容
import Hot from '../../entity/Content';
import router from '@ohos.router';
@Component
@Preview
export default struct Home { //导出,以便其它组件导入复用
  private menuItems: Array<string> = ['news1', 'news2', 'meet1', 'meet2', 'meet3'
    , 'meet4', 'meet5', 'meet6', 'meet7'];
  private strs: Array<string> = ['场馆动态', '运动常识', '足球场预约', '羽毛球场预约'
    , '篮球场预约', '乒乓球场预约', '网球场预约', '游泳馆预约', '健身房预约'];
  //声明对象数组,存取热门内容
  private Hots: Array<Hot> = [
    new Hot("ad2", "滑雪属于高危运动,这些安全常识你知道吗", "我们滑雪过程中如何做到尽兴又安全?首先,除了掌握熟练的滑雪技巧和灵活的应变能力,作好自身安全防护装备和快速准确的自我急救知识也是重要保障。", '2024-5-22'),
    new Hot("ad3", "享受自行车骑行的同时,也要注意这些事情", "骑行自行车时,应该保持良好的心态。不要过于紧张或者冒险,要放松心情,享受骑行的乐趣。", '2024-5-20'),
    new Hot("ad4", "去健身房锻炼时关注这些问题,做到文明健身!", "在健身房锻炼的时候,我们除了要文明健身外,还需要知道科学的健身流程,避免盲目瞎练。", '2024-5-20'),
    new Hot("ad1", "跑步做好这几项是非常有益的", "有些跑者换上装备就直接开跑,没有做充分的热身运动,这样抽筋,跟腱酸痛等毛病会很容易找上门。开始运动时,可以做循序渐进的方式,原地踏步,随后进行跨步,最后在活动一下各关节,这样就能降低跑步受伤的概率。", '2024-5-18')
  ]

  //ui设计
  build() {
    //{space:20}设置布局行间距
    Column() {
      //1.顶部第一行
      Row() {
        Image($r('app.media.indexbg'))
          .width('100%')
          .height('100%')
          .interpolation(ImageInterpolation.High)
      }
      .width('100%')
      .height('30%')

      //2.金刚区,也可以使用一个实体类来集中存储数据
      Row() {
        Grid() {
          ForEach(this.menuItems, (item: String,index:number) => {
            GridItem() { //只能有一个子组件
              Column() {
                Image('imgs/quicks/' + item + '.png').width(50).height(50)
                Text(this.strs[index])
              }.padding({ top: 13 })
            }.selectable(true) //设置能点击
            .onClick(() => { //通过索引号判断
              if (index == 0) {
                router.pushUrl({ url: 'pages/message/MyMessage', params: { myIndex: '0' } })
                //AlertDialog.show({message:'这是:'+index})
              } else if (index == 1) {
                router.pushUrl({ url: 'pages/know/MyKnow', params: { myIndex: '1' } })
              }else{//其它为场馆预约
                router.pushUrl({url:'pages/common/yuyuelist',params:{myIndex:index}})
              }
            })
          }) //fore
        } //grid
        //分列样式
        .columnsTemplate('1fr 1fr 1fr')
        .rowsGap(8)
      } //gird row
      .width('94%')
      .height(280)
      .backgroundColor('#fff')
      .borderRadius(10)
      .margin({ top: -20 })

      // 3.动态列表行,热门推荐
      List({ space: 12 }) { //行间距
        ForEach(this.Hots, (item: Hot) => {
          ListItem() { //只能有一个子组件
            Row() {
              //左边图片
              Image('imgs/types/' + item.pic + '.jpg').width(100).height(120)
                .borderRadius(8).margin({ right: 8 })
              Column() {
                //右边标题
                Text(item.title)
                  .width('94%')
                  .fontSize(24)
                  .fontWeight(FontWeight.Bold)
                  .textAlign(TextAlign.Center)
                  .maxLines(1) //保证只有一行后设为省略号
                  .textOverflow({ overflow: TextOverflow.Ellipsis })
                //右边内容
                Text(item.info)
                  .fontSize(16).padding({top:8})
                  .fontColor('#555')
                  .textAlign(TextAlign.Start)
                  .maxLines(3)
                  .textOverflow({ overflow: TextOverflow.Clip })
                  .align(Alignment.TopStart) //顶部左对齐,Top顶部居中
                  .width('92%')
                  .height(68)
                //发布时间
                Text(item.date).textAlign(TextAlign.End).width('92%').fontColor(Color.Grey)
                布局也要设置高宽
              }.padding({ top: 10, bottom: 10 })
              .justifyContent(FlexAlign.Start)
              .height('100%')
            }
          }
          .onClick(()=>{
            router.pushUrl({url:'pages/common/detail',params:{title:'运动常识',jsonstr:JSON.stringify(item)}})
          })
          .height('58%')
          .align(Alignment.Start)
          .backgroundColor(Color.White)
          .borderRadius(8)
          .padding({ right: 100 })
        }) //for
      }
      .width('94%')
      .height('100%')
      //不加布局权重,无法滑动
      .layoutWeight(1)
      .listDirection(Axis.Vertical)
      .margin({ top: 12})
      .backgroundColor('#eee')
    } //colum
  } //build
}

MyHome.ets组件:导入其它组件复用,并作为当前页渲染

//导入主页组件,并作为当前页的入口
import Home from './home';

@Entry
@Component
struct MyHome { //导出,以便其它组件导入应用
  build(){
    Row() {
      Home();
    }.width('100%')
     .height('100%')
  }

}

8、项目预览与部署

(1)预览效果

(2)模拟器部署效果

更多精彩内容请关注本站!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值