HarmonyOS NEXT - 项目基础框架的搭建

news2024/12/26 18:15:21

demo 地址: https://github.com/iotjin/JhHarmonyDemo
代码不定时更新,请前往github查看最新代码

HarmonyOS NEXT - 项目基础框架的搭建

  • 前置工作
  • 项目的目录结构
  • 主界面实现
  • BaseTabBar代码实现
  • 子页面实现
  • 路由跳转
  • 登录页面和主页面切换
  • 登录实现
  • 退出登录

项目基于鸿蒙 OpenHarmony SDK 5.0API12实现
主模块是entry模块,组件和工具类在JhCommon模块 ,通用图片资源放在了AppScope内,三方库在oh-package.json5管理。
项目的入口文件index.ets通过本地存储的用户信息判断是切换到登录页面还是主页面。

达到项目最低限度的要求要把项目结构定好,要可以网络请求,有一些必要组件和工具类,有登录页面和主页面,可以进行路由跳转

前置工作

  • 在demo中这些组件和工具类都通过module实现了,具体可以参考HarmonyOS NEXT - 通过 module 模块化引用公共组件和utils
  • HarmonyOS NEXT - 三方库axios的使用和封装
  • HarmonyOS NEXT - Navigation组件封装BaseNavigation
  • HarmonyOS NEXT - 数据持久化存储(key,value进行AES加密处理)

项目的目录结构

在这里插入图片描述

主界面实现

App的主页面是由三部分构成:Navigation+ 主体内容 + tabbar。所以需要创建Navigation组件和tabbar组件,然后通过路由连通单个页面
demo这里是使用BaseTabBar页面放置tabbar和4个子页面,子页面内部再实现Navigation+ 主体内容
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

BaseTabBar代码实现

import { OnePage } from './one/OnePage';
import { TwoPage } from './two/TwoPage';
import { ThreePage } from './three/ThreePage';
import { FourPage } from './four/FourPage';

export interface TabType {
  text: string,
  imgPath: string,
}

@Preview
@Entry
@Component
export struct BaseTabBar {
  @State currentIndex: number = 0
  tabsController: TabsController = new TabsController()
  tabList: TabType[] = [{
    imgPath: 'tab/nav_tab_1',
    text: '微信',
  }, {
    text: '通讯录',
    imgPath: 'tab/nav_tab_2',
  }, {
    text: '发现',
    imgPath: 'tab/nav_tab_3',
  }, {
    text: '我的',
    imgPath: 'tab/nav_tab_4',
  }]

  build() {
    Column() {
      Tabs({ barPosition: BarPosition.End }) {
        ForEach(this.tabList, (item: TabType, index: number) => {
          TabContent() {
            if (index == 0) {
              OnePage()
            } else if (index == 1) {
              TwoPage()
            } else if (index == 2) {
              ThreePage()
            } else {
              FourPage()
            }
          }
          .tabBar(this.TabBarBuilder(item.text, index, $rawfile(`${item.imgPath}.png`),
            $rawfile(`${item.imgPath}_on.png`)))
        })
      }
      .scrollable(false) //去掉左右滑动的效果
      .animationDuration(0) //去掉左右滑动的动画
      // .barHeight(156)
      .onChange((index: number) => {
        this.currentIndex = index
        this.tabsController.changeIndex(this.currentIndex)
      })
    }
    .backgroundColor("#eeeeee")
    .width('100%')
    .height('100%')
  }

  @Builder
  TabBarBuilder(title: string, index: number, normalImg: Resource, selectedImg: Resource) {
    Column() {
      Image(this.currentIndex == index ? selectedImg : normalImg)
        .width(24)
        .height(24)

      Text(title)
        .fontSize(14)
        .margin({ top: 4 })
        .fontColor(this.currentIndex == index ? '#45C461' : '#999999')
    }
    .backgroundColor(Color.White)
    .width('100%')
    .height(50)
    .padding({ top: 6, bottom: 6 })
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
    .id(`tabBar${index}`)
  }
}

子页面实现

这里只举列第一个页面,

import { router } from '@kit.ArkUI';
import { BaseNavigation } from 'JhCommon';

@Entry
@Component
export struct OnePage {
  @State message: string = 'One'

  build() {
    Column() {
      BaseNavigation({ title: "One", leftItem: {} })
      Button('DemoList').onClick(() => {
        router.pushUrl({ url: 'pages/demos/DemoListPage' })
      })
      RelativeContainer() {
        Text(this.message)
          .id('OnePage')
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
          .alignRules({
            center: { anchor: '__container__', align: VerticalAlign.Center },
            middle: { anchor: '__container__', align: HorizontalAlign.Center }
          })
      }
      .height('100%')
      .width('100%')
    }
  }
}

路由跳转

demo中都是通过@ohos.router实现的跳转,因为Router需要Navigation 包着页面的内容,多一层嵌套

页面路由 (@ohos.router)(不推荐)
Router切换Navigation

import { router } from '@kit.ArkUI';

router.replaceUrl({ url: 'pages/login/LoginPage' }) 
router.pushUrl({ url: 'pages/demos/DemoListPage' })

登录页面和主页面切换

切换通过在程序的第一个页面内处理,根据登录信息做判断显示登录页还是主页面

  build() {
    Column() {
      if (this.switchRootPage() == 'BaseTabBar') {
        BaseTabBar()
      } else {
        LoginPage()
      }
    }
    .backgroundColor("#eeeeee")
    .width('100%')
    .height('100%')
  }
  
  switchRootPage(): 'BaseTabBar' | 'LoginPage' {
    const userInfo = JhAESPreferencesUtils.getModel(kUserDefault_UserInfo)
    if (userInfo) {
      console.log('本地取出的 userInfo', JSON.stringify(userInfo))
      return 'BaseTabBar'
    } else {
      return 'LoginPage'
    }
  }

登录实现

import { router } from '@kit.ArkUI';
import { APIs, HttpUtils, JhAESPreferencesUtils, JhColorUtils, JhProgressHUD, kUserDefault_UserInfo, ResType } from 'JhCommon';
import { JhButton } from 'JhCommon/src/main/ets/JhCommon/components/JhButton';

@Entry
@Component
export struct LoginPage {
  @State @Watch('onChange') name: string = 'jin'
  @State @Watch('onChange') pwd: string = ''
  @State disabled: boolean = true

  // onChangeName(propName: string) {}
  // onChangePwd(propName: string) {}

  onChange() {
    let isClick = true
    if (this.name.length < 3) {
      isClick = false
    }
    if (this.pwd.length < 6) {
      isClick = false
    }
    this.disabled = !isClick
  }

  build() {
    Scroll() {
      Column() {
        Row() {
          Text('注册')
            .fontSize(18)
        }
        .justifyContent(FlexAlign.End)
        .width('100%')

        Row() {
          Text('Logo')
            .fontSize(20)
            .fontColor(Color.White)
        }
        .justifyContent(FlexAlign.Center)
        .alignItems(VerticalAlign.Center)
        .width(100)
        .height(100)
        .margin({ top: 80, bottom: 30 })
        .backgroundColor(JhColorUtils.randomColor())
        .borderRadius(50)

        TextInput({
          text: this.name,
          placeholder: '请输入用户名'
        })
          .height(50)
          .margin({ top: 20 })
          .onChange((value) => {
            this.name = value
          })
          .onSubmit((EnterKeyType) => {
            console.info(EnterKeyType + '输入法回车键的类型值')
          })
        TextInput({
          text: this.pwd,
          placeholder: '请输入密码',
        })
          .height(50)
          .type(InputType.Password)
          .margin({ top: 20 })
          .onChange((value) => {
            this.pwd = value
          })
          .onSubmit((EnterKeyType) => {
            console.info(EnterKeyType + '输入法回车键的类型值')
          })
        // Button('登录')
        //   .width('100%')
        //   .margin({ top: 50, bottom: 30 })
        //   .opacity(this.disabled ? 0.6 : 1)
        //   .backgroundColor(KColors.kThemeColor)
        //   .onClick(() => this.clickLogin())
        JhButton({
          text: '登录',
          disabled: this.disabled,
          onPressed: (): void => this.clickLogin()
        })
          .margin({ top: 50, bottom: 30 })
        Row() {
          Text('验证码登录')
            .fontSize(18)
          Text('忘记密码')
            .fontSize(18)
        }
        .justifyContent(FlexAlign.SpaceBetween)
        .width('100%')
      }
      .alignItems(HorizontalAlign.Center)
      .justifyContent(FlexAlign.Start)
      .height('100%')
      .width('100%')
      .padding(15)
    }
  }

  clickLogin() {
    const params: object = Object({ 'userName': this.name, 'pwd': this.pwd })
    HttpUtils.post(APIs.login, params, '正在登录...').then((res: ResType) => {
      console.log('登录返回数据:', JSON.stringify(res))
      JhProgressHUD.showSuccess(res.msg)
      JhAESPreferencesUtils.saveModel(kUserDefault_UserInfo, res.data)
      router.replaceUrl({ url: 'pages/BaseTabBar' })
    })
  }
}

退出登录

退出登录把用户信息清掉,并把路由替换掉即可

import { router } from '@kit.ArkUI';

exitLogin() {
    JhProgressHUD.showLoadingText('正在退出...')
    setTimeout(() => {
      JhAESPreferencesUtils.delete(kUserDefault_UserInfo)
      router.replaceUrl({ url: 'pages/login/LoginPage' })
      JhProgressHUD.hide()
    }, 1000)
  }

至此大框架已经出来了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2046877.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spark-环境启动

一、概览 从start-all.sh开始捋&#xff0c;一直捋到Master、Worker的启动并建立通信 二、宏观描述 Master端 1、start-all.sh调用start-master.sh启动Master 2、执行org.apache.spark.deploy.master.Master中main方法 3、通过工厂模式创建RpcEnv子类NettyRpcEnv a、创建…

viper配置文件读取管理库 一个支持12种文件类型,5种远程协议的配置文件管理和加载工具库 使用方法示例

viper是一个不错的配置文件管理库&#xff0c; 他支持的配置文件类型依次有 "json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "tfvars", "dotenv&quo…

java:实现简单的验证码功能

效果 实现思路 验证码图片的url由后端的一个Controller生成&#xff0c;前端请求这个Controller接口的时候根据当前时间生成一个uuid&#xff0c;并把这个uuid在前端使用localStorage缓存起来&#xff0c;下一次还是从缓存中获取。 Controller生成验证码之后&#xff0c;把前…

Qt 学习第六天:页面布局

如何设计页面&#xff1f; 有个类似沙盒模式的玩法&#xff0c;Qt Widget Designer可以更好的帮助我们设计页面 点击.ui文件进入 右上方可以看到四种常见的布局&#xff1a; 四种布局 &#xff08;一&#xff09;水平布局horizontalLayout&#xff1a;QHBoxLayout H 是 hori…

c++实现B树(上)

哈喽啊&#xff01;好久不见&#xff0c;甚是想念&#xff01;失踪人口要回归了&#xff0c;时隔一个多月小吉我终于要更新blog了&#x1f389;。在停更的一个多月中&#xff0c;小吉也有在好好学习提升自己&#xff0c;立志给大家呈现好文章。  现在让我们进入正题吧&#xf…

初识C++:开启C++之旅

目录 1.C的第一个程序 2.namesapce命名空间域 2.1namespace的意义 2.2.2namespace的定义 2.3命名空间的使用 3.C输入/输出 4.缺省参数 5.函数重载 6.引用 6.1引用的特性 6.2引用的使用 1.C的第一个程序 c版本&#xff1a; #include<iostream>using std::cout…

kali安装wechart

前言&#xff1a; 突发奇想想在kali安装个wechart&#xff0c;试了下网上的很多&#xff0c;玩坏了一个虚拟机算是找到了一个不错的方法&#xff0c;这里记录下&#xff0c;防迷路 基础配置&#xff1a; 首先修改源&#xff1a; vim /etc/apt/sources.list 注释默认配置&…

EasyCVR视频汇聚平台:打造全栈视频监控系统的基石,解锁可视化管理与高效运维

随着科技的飞速发展&#xff0c;视频监控已成为现代社会不可或缺的一部分&#xff0c;广泛应用于社区、公共场所、工业领域等多个场景。EasyCVR视频汇聚平台&#xff0c;作为一款高性能的视频汇聚管理平台&#xff0c;凭借其强大的视频处理、汇聚与融合能力&#xff0c;在构建全…

centos8 安装zookeeper

1&#xff1a;下载 zookeeper官网 解压&#xff1a;tar -zxvf apache-zookeeper-3.6.3.tar.gz 修改自己想要的文件目录 mv apache-zookeeper-3.6.3 zookeeper_3.6.3 备份一下 配置文件 cp zoo_sample.cfg zoo.cfg vim zoo.cfg 编辑日志文件和端口号

nginx实战演练

目录 一.Nginx架构和安装&#xff08;未完待续&#xff09; <1>.Nginx概述 <2>.Nginx架构和进程 <3>.Nginx模块 <4>.Nginx安装(编译安装) 二.Nginx基础配置 <1>.关闭debug <2>.将nginx软件添加到环境变量 <3>.开机自启动脚…

EmguCV学习笔记 VB.Net 2.5 Mat类、Matrix类和Image类的相互转换

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 EmguCV学习笔记目录 Vb.net EmguCV学习笔记目录 C# 笔者的博客网址&#xff1a;VB.Net-CSDN博客 教程相关说明以及如何获得pdf教…

基于Vue的MES生产制造执行系统

TOC springboot307基于Vue的MES生产制造执行系统 第1章 绪论 1.1 选题动因 到现在为止&#xff0c;互联网已经进入了千家万户&#xff0c;最普通的平民百姓也有属于自己的智能设备&#xff0c;计算机各种技术的储备也是相当的丰富&#xff0c;并且实现也是没有难度&#xf…

VSCode配置ssh免密连接远程服务器

我配置了免密设置(Windows利用ssh免密码登录Linux)&#xff0c;git bash已经能够正常连接了&#xff0c;但是vscode还是不行&#xff0c;很奇怪。 VSCode报错信息&#xff1a; [17:55:50.360] SSH Resolver called for "ssh-remote106.52.2.19", attempt 5, (Recon…

《机器学习》——运用OpenCV库中的KNN算法进行图像识别

文章目录 KNN算法的简单介绍下载OpenCV库实验内容实验结果完整代码自己手写数字传入模型中测试 KNN算法的简单介绍 一、KNN算法的基本要素 K值的选择&#xff1a;K值代表选择与新测试样本距离最近的前K个训练样本数&#xff0c;通常K是不大于20的整数。K值的选择对算法结果有重…

电压检测之比较电路

设计这款电路主要是本人在锂电池充电电路中挖了一个坑&#xff0c;对电源显示芯片的数据手册内容撰写不够详细的不好感受&#xff0c;所以自己根据比较电路的思想设计出了电压检测并反馈的电路&#xff0c;亦在提供一种电压检测的思想不需要借助ADC采集&#xff0c;在电路硬件上…

基于hive的海鲜交易数据分析系统设计与实现【hadoop、Flask、某东爬虫、sqoop、flume、mysql、hdfs】商品可换

文章目录 有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主项目介绍研究背景国内外研究现状研究目的研究意义 关键技术理论介绍数据采集及预处理数据采集字段介绍数据预处理hadoop集群搭建及实现过程hive建表hive大数据分析 可视化展示店铺维度画像分…

AR 眼镜之-开关机定制-实现方案

目录 &#x1f4c2; 前言 AR 眼镜系统版本 开关机定制 1. &#x1f531; 技术方案 1.1 技术方案概述 1.2 实现方案 1&#xff09;开机 Logo 2&#xff09;开机音效 3&#xff09;开机动画 4&#xff09;关机动画 5&#xff09;关机弹窗 2. &#x1f4a0; 开机 Logo…

C++笔试题汇总

C笔试题汇总记录 一、概述二、概念分类1. 结构体1. C 和 C 中 struct 有什么区别&#xff1f;2. C中的 struct 和 class 有什么区别&#xff1f; 2. 类相关1. 类的大小1. 空类的大小2. 一般非空类大小3. 有虚函数类4. 有虚函数类的继承5. 只有虚函数6. 静态数据成员 2. C的三大…

【分享】格力手机色界G0245D 刷REC、root、 救砖、第三方rom教程和资源

开门见山 帮别人弄了一台 格力G0245D&#xff0c;把找到的资源和教程分享一下 教程 这个写的很详细了格力手机色界G0245D-Root-最简指南 不过教程里刷rec这一步漏了加上电源键&#xff0c;加上就行了。 附加参考&#xff1a;格力手机2刷机 格力手机二代刷机 GREE G0215D刷机…

C++ 特殊类设计以及单例模式

目录 1 不能被拷贝 2 只能在堆上创建对象 3 只能在栈上创建对象 4 禁止在堆上创建对象 5 不能被继承的类 6 单例类 特殊类就是一些有特殊需求的类。 1 不能被拷贝 要设计一个防拷贝的类&#xff0c;C98之前我们只需要将拷贝构造以及拷贝赋值设为私有&#xff0c;同时只声明…