引言
由于公司開始支持鴻蒙生態(tài)肉瓦,小編也開啟了鴻蒙純血NEXT
版本的應用開發(fā)银还。
本篇主要整理總結(jié)實戰(zhàn)項目中遇到的問題及重點知識內(nèi)容戒财。適合使用ArkTS進行鴻蒙NEXT及以上版本開發(fā)的初學者列吼、進階學習者理郑。
內(nèi)容分為以下幾個維度柒爵,歡迎大家一起交流學習。
ArkTS 語言
使用ArkTs語言進行開發(fā)唁奢,了解如下兩點即可
1. 數(shù)據(jù)類型
ArkTS支持的數(shù)據(jù)類型如下:
Object驮瞧、string论笔、number、boolean蒜埋、enum 整份、Array籽孙、union犯建、void适瓦、aliases、Record否彩、Map 等列荔。
下面列舉一些個例的特性:
// string
undefined == name?:string
// Array
let name: string[] = ['rex','bob']
// union | 聯(lián)合類型
type Animal = Cat | Dog
let animal : Animal = new Cat()
animal = new Dog()
// aliases | 匿名類型
type Predicate <T> = (x: T) => Boolean;
type NullableObject = Object | null;
// Record<K,V> | Record 與 Map 的區(qū)別是 Record 不需要 new肌毅,Map 需要 new
let map: Record<string, number> = {
'John': 25,
'Mary': 21,
}
2. 語法特點
ArkTS的語法與其他前端語言大同小異,下面列舉一些個例的特性:
// Rest參數(shù)
fun sum(...numbers: number[])
sum()
sum(1,2,3)
// 定義回調(diào)
type trigFunc = (x:number) => number
function do_action(f: trigFunc)
// 閉包
function f(): () => number {
let count = 0;
return (): number => { count++; return count; }
}
let z = f();
z(); // 返回:1
z(); // 返回:2
// 可選參數(shù)
function hello(name?: string) // name == undefined
function multiply(n: number, coeff: number = 2)
nultiply(1)
// 字段不復值時默認值是 undefined
// 構(gòu)造函數(shù)需要使用關(guān)鍵字
constructor(n: string, a: number)
// 模塊導出
export let Origin = new Point(0, 0);
export function Distance(p1: Point, p2: Point): number{ *** }
// 模塊導入
import * as Utils from './utils' // Utils.X
import { X, Y } from './utils'
X // 表示來自utils的X
Y // 表示來自utils的Y
// 聲明
readonly height : number = 1 //只讀
let hi: string = 'hello' //變量
const hello: string = 'hello' //常量
// 空安全
let x: number | null = null
// 接口 interface
interface W {
bundleName: string
action: string
entities: string[]
}
let wantInfo: W = {
bundleName: 'com.huawei.hmos.browser',
action: 'ohos.want.action.viewData',
entities: ['entity.system.browsable']
}
PS:需要注意的是锭汛,字符串里插入變量要使用`符號而不是單引號或雙引號唤殴,如下:
Text(`插入變量到字符串中的值為${this.number}`)
HarmonyOS 的項目結(jié)構(gòu)
關(guān)于 HarmonyOS 的項目包結(jié)構(gòu)朵逝,我們暫時不需要做到全盤掌握,了解如下幾個知識點即可:
1. 項目類型
創(chuàng)建項目分為兩種類型啤咽,分別是 app(應用)宇整、atomicService(元服務(wù))
這兩種類型的項目創(chuàng)建后的包結(jié)構(gòu)是一樣的鳞青,代碼編輯也一致臂拓。重點差異如下:
- 元服務(wù)類似于微信小程序习寸,用戶可直接在手機的負一層頁面搜索使用融涣,無需下載
- 元服務(wù)的開發(fā)api是應用的開發(fā)api的子集,即有些api在開發(fā)應用時可用剃斧,在開發(fā)元服務(wù)時不可用幼东。
2. 模塊類型
創(chuàng)建模塊分為三種類型根蟹,分別是 hap糟秘、har尿赚、hsp
- HAP:應用安裝和運行的基本單元,分為兩種類型:entry和feature
- HAR:靜態(tài)共享包 (可以理解為封裝的 Library屋讶,里面可以存放代碼和資源皿渗,提供給 hap 或者 har 模塊進行引用)
- HSP:動態(tài)共享包(一般應用不常用)
3. 重點文件
- app.json5 :bundleType 標識 元服務(wù)(atomicService)或 應用(app)
- module.json5 :stage模型模塊配置文件乐疆,type 標識模塊類型(entry约计、hap煤蚌、har尉桩、share)
- oh-package.json5 :配置三方包聲明文件的入口及包名
最后展示一張項目的包結(jié)構(gòu)截圖:
UI 開發(fā)中的實用技巧
1. 單位
- fp: 字體像素單位蜘犁,隨系統(tǒng)字體大小設(shè)置變化
- vp: 密度像素單位
//使用示例
Text('示例').fontSize('16fp').widht('100vp')
2. @Extend
定義擴展組件樣式
@Extend(Column)
function ColumnStyle() {
.width('100%')
.borderRadius(24)
.backgroundColor(Color.White)
.padding({ left: 12, right: 12, bottom: 4, top: 4 })
}
Column(){}.ColumnStyle()
3. @Styles
定義組件重用樣式
@Styles fancy() {
.width(200)
.height(this.heightValue)
.backgroundColor(Color.Yellow)
.onClick(() => {
this.heightValue = 200
})
}
Text().fancy()
4. 自定義組件 @Builder 和 @BuilderParam
@Component
struct Child {
@Builder FunABuilder0() {}
@BuilderParam aBuilder0: () => void = this.FunABuilder0;
build() {
Column() {
this.aBuilder0()
}
}
}
@Entry
@Component
struct Parent {
@Builder componentBuilder() {
Text(`Parent builder `)
}
build() {
Column() {
Child({ aBuilder0: this.componentBuilder })
}
}
}
5. 生命周期
- 自定義組件:@Component裝飾的UI單元奏窑,可以調(diào)用組件的生命周期屈扎。
- 頁面:可以由一個或者多個自定義組件組成鹰晨,只有被@Entry裝飾的組件才可以調(diào)用頁面的生命周期模蜡。
- onPageShow:頁面每次顯示時觸發(fā)一次,包括路由過程闯传、應用進入前臺等場景丸边,僅@Entry裝飾的自定義組件生效。
- onPageHide:頁面每次隱藏時觸發(fā)一次,包括路由過程骄呼、應用進入后臺等場景蜓萄,僅@Entry裝飾的自定義組件生效嫉沽。
- onBackPress:當用戶點擊返回按鈕時觸發(fā)俏竞,僅@Entry裝飾的自定義組件生效魂毁。
- aboutToAppear:組件即將出現(xiàn)時回調(diào)該接口席楚,具體時機為在創(chuàng)建自定義組件的新實例后烦秩,在執(zhí)行其build()函數(shù)之前執(zhí)行只祠。
- aboutToDisappear:aboutToDisappear函數(shù)在自定義組件析構(gòu)銷毀之前執(zhí)行。不允許在aboutToDisappear函數(shù)中改變狀態(tài)變量牺氨,特別是@Link變量的修改可能會導致應用程序行為不穩(wěn)定猴凹。
HarmoneyOS 的狀態(tài)管理
1. 組件的狀態(tài)管理
建議看一遍官網(wǎng)的示例
2. 應用的狀態(tài)管理
PS:重點提一下 LocalStorage 和 AppStorage 的區(qū)別郊霎,LocalStorage 是頁面級存儲爷绘、頁面內(nèi)共享,而 AppStorage 是可以跨 Ability 共享的猾昆。(即適用于多hap項目)
應用開發(fā)中常用方法
1. Toast 的使用
promptAction.showToast({
message: $r('app.string.success_message'),
duration: 2000
})
2. Preferences 的使用
import dataPreferences from '@ohos.data.preferences';
//聲明
let dataPreferencesManager: dataPreferences.Preferences = {} as dataPreferences.Preferences;
//獲取實例
let options: dataPreferences.Options = { name: 'myStore', dataGroupId:'myId' };
dataPreferences.getPreferences(this.context, options, (err: BusinessError, val: dataPreferences.Preferences) => {
if (err) {
return;
}
preferences = val;
})
//put
dataPreferencesManager.push(key,value)
dataPreferencesManager.flush()
3. Context
/// 實現(xiàn)全局Context
// 在 EntryAbility 的 create 方法中綁定上下文
AppStorage.setOrCreate('context', this.context);
//獲取全局Context
AppStorage.get('context')
/// UI頁面獲取局部Context
const CONTEXT: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
4. JSON 與 Object 的轉(zhuǎn)換
/// JSON to Object
/// 方案一:
class A {
v: number = 0
s: string = ''
fromJson (str: string) {
let tmpStr: Record<string, Object> = JSON.parse(str);
if (tmpStr.add != undefined) {
this.v = tmpStr.v as number;
this.s = tmpStr.s as string;
}
}
}
/// 方案二:
let json: string = '{"name":"rex","age":"10"}'
class Student {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
let student = JSON.parse(json) as Student;
/// Object to Json(String)
JSON.stringify(any)
5. Http 的使用
使用官方提供的HTTP模塊:
// 引入包名
import http from '@ohos.net.http';
import { BusinessError } from '@ohos.base';
// 每一個httpRequest對應一個HTTP請求任務(wù),不可復用
let httpRequest = http.createHttp();
// 用于訂閱HTTP響應頭贴见,此接口會比request請求先返回片部〉涤疲可以根據(jù)業(yè)務(wù)需要訂閱此消息
// 從API 8開始然爆,使用on('headersReceive', Callback)替代on('headerReceive', AsyncCallback)曾雕。 8+
httpRequest.on('headersReceive', (header) => {
console.info('header: ' + JSON.stringify(header));
});
httpRequest.request(
// 填寫HTTP請求的URL地址剖张,可以帶參數(shù)也可以不帶參數(shù)搔弄。URL地址需要開發(fā)者自定義。請求的參數(shù)可以在extraData中指定
"EXAMPLE_URL",
{
method: http.RequestMethod.POST, // 可選倒庵,默認為http.RequestMethod.GET
// 開發(fā)者根據(jù)自身業(yè)務(wù)需要添加header字段
header: [{
'Content-Type': 'application/json'
}],
// 當使用POST請求時此字段用于傳遞內(nèi)容
extraData: "data to send",
expectDataType: http.HttpDataType.STRING, // 可選擎宝,指定返回數(shù)據(jù)的類型
usingCache: true, // 可選绍申,默認為true
priority: 1, // 可選极阅,默認為1
connectTimeout: 60000, // 可選筋搏,默認為60000ms
readTimeout: 60000, // 可選,默認為60000ms
usingProtocol: http.HttpProtocol.HTTP1_1, // 可選儒旬,協(xié)議類型默認值由系統(tǒng)自動指定
usingProxy: false, //可選,默認不使用網(wǎng)絡(luò)代理竖般,自API 10開始支持該屬性
}, (err: BusinessError, data: http.HttpResponse) => {
if (!err) {
// data.result為HTTP響應內(nèi)容涣雕,可根據(jù)業(yè)務(wù)需要進行解析
console.info('Result:' + JSON.stringify(data.result));
console.info('code:' + JSON.stringify(data.responseCode));
// data.header為HTTP響應頭挣郭,可根據(jù)業(yè)務(wù)需要進行解析
console.info('header:' + JSON.stringify(data.header));
console.info('cookies:' + JSON.stringify(data.cookies)); // 8+
// 當該請求使用完畢時疗韵,調(diào)用destroy方法主動銷毀
httpRequest.destroy();
} else {
console.error('error:' + JSON.stringify(err));
// 取消訂閱HTTP響應頭事件
httpRequest.off('headersReceive');
// 當該請求使用完畢時流译,調(diào)用destroy方法主動銷毀
httpRequest.destroy();
}
}
);
PS:后期小編會封裝一個簡化代碼的靜態(tài)庫提供使用
6. 路由的選擇與使用
路由提供兩種選擇方案:
組件 | 適用場景 | 特點 | 轉(zhuǎn)場動畫效果對比 |
---|---|---|---|
Router | 模塊間與模塊內(nèi)頁面切換 | 通過每個頁面的url實現(xiàn)模塊間解耦 | 頁面平推轉(zhuǎn)場效果 |
NavPathStack | 模塊內(nèi)頁面切換 | 通過組件級路由統(tǒng)一路由管理 | 向右折疊轉(zhuǎn)場效果 |
- Router的使用
router.pushUrl({
url: 'pages/routerpage2',
params: new routerParams('message' ,[123,456,789])
})
/// url 對應 resource - profile - mainpages.json
- NavPathStack的使用
小編使用的方案是 NavPathStack 福澡,下面來重點說說使用方式革砸。
NavPathStack
是配合 Navigation
一起使用的算利,
Navigation導航組件做統(tǒng)一的頁面跳轉(zhuǎn)管理寇蚊,它提供了一系列屬性方法來設(shè)置頁面的標題欄、工具欄以及菜單欄的各種展示樣式仗岸。
//第一步允耿,需要在應用的根頁面自行維護 navStack 實例借笙,并傳遞給根節(jié)點 Navigation
@Provide('pageInfos') pageInfos: NavPathStack = new NavPathStack()
Navigation(this.pageInfos) {
Column() {}
}
.title('NavIndex')
.navDestination(this.PageMap)
// 統(tǒng)一管理維護路由跳轉(zhuǎn)
@Builder
PageMap(name: string) {
if (name === 'pageOne') {
PageOneTmp()
} else if (name === 'pageTwo') {
pageTwoTmp()
}
}
// 第二步,注意较锡,目標跳轉(zhuǎn)頁面節(jié)點需要使用 NavDestination 進行包裹
// 目標跳轉(zhuǎn)頁面,例如 PageOneTmp
@Component
export struct PageOneTmp {
build(){
NavDestination(){
Column(){
}
}
}
}
/// 如何跳轉(zhuǎn)
this.pageInfos.pushPathByName('pageOne', null)
附注
Demo 示例已上傳:
GitHub:https://github.com/liyufengrex/HarmonyAtomicService
GitCode:https://gitcode.com/liyufengrex/HarmonyAtomicService
(基于API11開發(fā)业稼,支持NEXT及以上版本運行)已上傳可供參考,包含如下內(nèi)容:
- 靜態(tài)庫+動態(tài)包+多模塊設(shè)計
- 狀態(tài)管理
- 統(tǒng)一路由管理(router+navPathStack)
- 網(wǎng)絡(luò)請求蚂蕴、Loading 等工具庫封裝
- 自定義組件低散、自定義彈窗(解耦)
- EventBus 事件通知
- 擴展修飾器骡楼,實現(xiàn) 節(jié)流熔号、防抖、權(quán)限申請
- 動態(tài)路由 (navPathStack + 動態(tài)import + WrappedBuilder)
- UI動態(tài)節(jié)點操作 (BuilderNode + NodeController)
- 折疊屏適配示例
- 組件工廠示例
- 組件動態(tài)屬性設(shè)置示例
- 云函數(shù)鸟整、云數(shù)據(jù)庫使用示例
- 華為賬號服務(wù)示例(快速登陸引镊、快速驗證手機號)