demo 地址: https://github.com/iotjin/JhHarmonyDemo
代码不定时更新,请前往github查看最新代码
HarmonyOS NEXT - 项目基础框架的搭建
- 序
- 前置工作
- 项目的目录结构
- 主界面实现
- BaseTabBar代码实现
- 子页面实现
- 路由跳转
- 登录页面和主页面切换
- 登录实现
- 退出登录
序
项目基于鸿蒙
OpenHarmony SDK 5.0
,API12
实现
主模块是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)
}
至此大框架已经出来了