HarmonyOS知识点

devtools/2024/11/19 13:49:44/

HarmonyOS应用模型Stage&FA 、ArkTS、ArkUI
Stage模型:
Module - UIAbility - Page - component

装饰器@Entry、@Component、@CustomDialog、@State、关键字struct、函数build()

系统组件(Text Column Row Scroll)、自定义组件 、组件复用、组件事件、组件属性、组件状态(能够对对象深度响应式改变)

在arkUI中,我们的内容如果超过了屏幕显示,则不会显示滚动条,需要使用Scroll来包裹
需要注意的是: 该组件滚动的前提是主轴方向大小小于内容大小。子组件不要设置高度,否则不能滚动

样式(链式&枚举)
vp和适配(伸缩布局,网格系统,栅格系统)
vp 是鸿蒙默认单位,和屏幕像素有关,最终表现视觉大小在任何设备一致
1、伸缩 layoutWeight(flex: number) 占剩余空间多少份,可以理解成CSS的 flex: 1
2、内容等比例缩放-可以使用aspectRatio属性设置宽高比

Image的四种使用方式

1、使用本地图片  Image('/assets/test.jpg')  /src/main/ets/assets/test.jpg
2、使用资源引入 Resource 类型  Image(\$r("app.media.test"))  /src/main/resources/base/media/test.jpg
3、采用原始文件引入  Image(\$rawfile('test.jpg'))  /src/main/resources/rawfile/test.jpg
4、引用网络图片 Image("https://...")   在模拟器中需要在module.json5文件中配置网络权限才能显示

垂直水平居中
.alignItems(VerticalAlign.Center)
.justifyContent(FlexAlign.Center)

@Styles复用、@Extend复用

StateStyle(正常态normal,按压态pressed,获焦态focused,禁用态disabled)样式抽离只能抽离到组件内,不能抽离到全局

if else 创建销毁,opacity隐藏后占位置,visibility: Visibility.Hidden占位置, visibility: Visibility.None不占位置

数据父传子,事件父传子实现数据子传父

// 把子组件的item传给父组件
// 子
public item: Partial<ReplyItem> = {} // 非响应式数据
public changeLike: (params: ReplyItem) => void = () => {}
.onClick(()=>{this.changeLike(this.item as ReplyItem)
})
// 父
MainItem({item: item, changeLike: (obj: ReplyItem)=>{this.changeLike(obj)
}})
changeLike(obj: ReplyItem){......
}
// Partial 把需要传入的对象ReplyItem内的属性变为可选的(可传可不传)
public item: Partial<ReplyItem> = {} // 非响应式数据
// this.item 属性都是可选的,使用 as 规避类型错误,强制认为ReplyItem内有属性有值
this.changeLike(this.item as ReplyItem)

构建函数
@Builder - 自定义构建函数,复用单元,对于修改响应式数据只能修改按引用传递(obj)不能按值传递参数(string)

@BuilderParam 类似于Vue中slot插槽的作用,只能应用在Component组件中,不能使用Entry修饰的组件中使用。尾随闭包、

@Builder setBtn() {Button('你好')
}
Card({getContent: this.setBtn})
// Card
@BuilderParam getContent: () => void = () => {}
this.getContent()

@Prop单向数据流(父变子变,子变父不变)
@Link双向绑定 注意:Link修饰的数据必须得是最外层的 State数据,不能传变化后的,比如forEach里的参数item就不允许传

状态共享-后代组件
父@Provide定义 和 子@Consume接收

@Watch监听

@Observed修饰类与@ObjectLink接收,可以解决@Link弊端,如上面提到的forEach里的参数item就不允许传到@link,此时就可以传item了
@ObjectLink不能整体赋值,只能对里面的属性赋值

@ObjectLink upClass: UploadClass
@Observed
class UploadClass {images: ImageList[] = []
}
多层state修改
this.user.address.city = "廊坊"
this.user.address = new IAddressModel(this.user.address)

border-bottom属性设置

.border({width: 1,color: {left: Color.White,right: Color.White,top: Color.White,bottom: Color.Black},
})
// 实现软键盘弹出后,整体布局不变
.expandSafeArea([SafeAreaType.KEYBOARD]) 
// 键盘避让
windowStage.getMainWindowSync().getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.RESIZE)
// 关闭输入法软键盘
inputMethod.getController().stopInputSession()
// 主动调起软键盘
focusControl.requestFocus('input_id')

LocalStorage、AppStorage

持久化的数据
PersistentStorage.PersistProp<string>("user_cart", "[]")
页面生命周期
aboutToAppear: 页面初始化触发一次。
onPageShow: 页面每次显示时触发。
onPageHide: 页面每次隐藏时触发一次。
aboutToDisAppear: 页面销毁时触发一次。
onBackPress: 当用户点击返回按钮时触发。自定义组件生命周期
aboutToAppear:组件即将出现时回调该接口,具体时机为在创建自定义组件的新实例后,在执行其build()函数之前执行。
aboutToDisappear:在自定义组件即将析构销毁时执行UIAbility生命周期
UIAbility的生命周期包括Create、Foreground、Background、Destroy四个状态
创建到销毁的过程
onCreate - onWindowStageCreate- onForeground - onBackground - onWindowStageDestroy - onDestroy

ability通信

// abilityA - 页面
const context = getContext(this) as common.UIAbilityContext
let want: Want = {bundleName: 'com.example.helloworld', // 包名 AppScope/app.json5 app.bundleNameabilityName: 'HeimaPayAbility', // HeimaPay/src/main/module.json5moduleName: 'HeimaPay',parameters: {order_id: Date.now()}
}
const result = await context.startAbilityForResult(want) //拉起另外一个ability并接收另外一个ability的返回值
const params =   result.want.parameters as ResultParams
type  ResultParams = Record<string, boolean> // Record相当于Map,定义一个键值对类型
// abilityB
type AbilityParams = Record<string, number>
onCreate(want: Want, launchParam) {const params = want.parameters as AbilityParams// 将参数设置到AppStorageAppStorage.SetOrCreate<number>("order_id",  params.order_id )
}
// abilityB - 页面
// 销毁当前的ability 将支付结果告诉调用我的人
const context = getContext(this) as  common.UIAbilityContext
context.terminateSelfWithResult({resultCode: 1,want: {abilityName: 'EntryAbility',bundleName: 'com.example.helloworld',moduleName: 'entry',parameters: {paySuccess: true}}
})

通知发布,通知唤起ability

// 发起一个通知
notificationManager.publish({content: {contentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,normal: {title: "温馨提示",text: "您有一个新订单",additionalText: "订单提醒"}},wantAgent: await wantAgent.getWantAgent({ // 点击通知拉起一个abilitywants: [{bundleName: "com.example.mylogisticsapp01", //包名在最上面AppScope里 app.json5abilityName: "ListenAbility",parameters: {order_id: Date.now()}}],operationType: wantAgent.OperationType.START_ABILITY,requestCode: 0})
})

路由传值

路由模式
● Standard:标准实例模式,也是默认情况下的实例模式。每次调用该方法都会新建一个目标页,并压入栈顶。
● Single:单实例模式。即如果目标页的url在页面栈中已经存在同url页面,则离栈顶最近的同url页面会被移动到栈顶,并重新加载;如果目标页的url在页面栈中不存在同url页面,则按照标准模式跳转。
简单理解
1. Standard-只要你push,页面栈里面就会加一项,不管之前加没加过
2. Single- 你之前加过,不会加新的页面,会把你之前加过的页面加出来
router.pushUrl({url: 'pages/CarRecord/CarRecord',params: {id: this.taskDetailData.id}
})
// 接收
const params = router.getParams() as CommonRouterParams
if (params && params.id) {}
// 类型
export class CommonRouterParams {id?: string = ''
}

震动

import vibrator from '@ohos.vibrator';
vibrator.startVibration({ duration: 300, type: 'time' }, { id: 0, usage: 'touch' })

声音播放

AVPlayerClass.playAudio("success.wav", getContext(this)) // 单例 音频播放都通过这一个单例 也不需要new
// 播放类  单例
export class AVPlayerClass {// 调用之前不希望创建avPlayer  所以给个联合类型null  默认是nullstatic avPlayer: media.AVPlayer | null = nullstatic audioName: string = "" //存储当前的音频的名称static isSettingBack: boolean = false // 是否设置过回调 因为针对某一个player只能设置一次回调// 提供一个只播放音乐的静态方法static async playAudio(audioName: string, context: Context) {if (!AVPlayerClass.avPlayer) {AVPlayerClass.avPlayer = await media.createAVPlayer()}//如果audio有值if (audioName) {// 将这个值对应的音频文件读过来给avPlayer的fdSrcAVPlayerClass.audioName = audioNameAVPlayerClass.setAvPlayerAudio(context)}}// 注册avplayer回调函数static setAVPlayerCallback() {// seek操作结果回调函数AVPlayerClass.avPlayer.on('seekDone', (seekDoneTime: number) => {// console.info(`AVPlayer seek succeeded, seek time is ${seekDoneTime}`);AVPlayerClass.avPlayer!.play()//回到0秒后 才播放   播完了就会走到 case 'completed': 需要重置})// error回调监听函数,当avPlayer在操作过程中出现错误时调用 reset接口触发重置流程// 状态机变化回调函数AVPlayerClass.avPlayer!.on('stateChange', async (state: string, reason: media.StateChangeReason) => {switch (state) {// case 'idle': // 成功调用reset接口后触发该状态机上报//   console.info('AVPlayer state idle called.');//   AVPlayerClass.avPlayer.release(); // 调用release接口销毁实例对象//   break;case 'initialized': // avplayer 设置播放源后触发该状态上报console.info('AVPlayer state initialized called.');AVPlayerClass.avPlayer!.prepare();//准备播放           ! 是类型的非空断言break;case 'prepared': // prepare调用成功后上报该状态机console.info('AVPlayer state prepared called.');AVPlayerClass.avPlayer!.seek(0); // 调用播放接口开始播放  //将音频的播放进度挪到0的位置break;case 'playing': // play成功调用后触发该状态机上报break;case 'paused': // pause成功调用后触发该状态机上报console.info('AVPlayer state paused called.');break;case 'completed': // 播放结束后触发该状态机上报console.info('AVPlayer state completed called.');AVPlayerClass.avPlayer.reset(); // 调用reset接口初始化avplayer状态  //重置了break;case 'stopped': // stop接口成功调用后触发该状态机上报console.info('AVPlayer state stopped called.');break;case 'released':console.info('AVPlayer state released called.');break;default:console.info('AVPlayer state unknown called.');break;}})}static async setAvPlayerAudio(context: Context) {//AVPlayerClass.audioNamelet fileDescriptor = await context.resourceManager.getRawFd(AVPlayerClass.audioName)let avFileDescriptor: media.AVFileDescriptor ={ fd: fileDescriptor.fd, offset: fileDescriptor.offset, length: fileDescriptor.length };if (!AVPlayerClass.isSettingBack) {// 设置回调 回调只能设置一次AVPlayerClass.setAVPlayerCallback()}if (AVPlayerClass.avPlayer) {// 拿到了资源 赋值给播放器的src属性  意味着会走回调AVPlayerClass.avPlayer.fdSrc = fileDescriptor;}}
}

动画
显式动画(animateTo)和属性动画(animation)

.onClick(() => {animateTo({duration: 500}, () => {this.showCom = !this.showCom})
})
Image($r("app.media.test")).transition({type: TransitionType.Insert,rotate: {angle: -360}}).transition({type: TransitionType.Delete,rotate: {angle: 360}})

混合开发sdk通信

Web({ src: $rawfile('location.html'), controller: WebSdkClass.controller! }).height('100%').width('100%').javaScriptProxy({object: this.webSdk,name: 'shenling',methodList: ['alert', 'toast', 'getLocation', 'receiveData'],controller: WebSdkClass.controller!})
// location.html
shenling.receiveData("search_list",JSON.stringify(result?.poiList?.pois || []))
// web_sdk.ets
export class WebSdkClass {static controller: Webview.WebviewController | null = nullstatic context: Context | null = nullalert(msg: string) {AlertDialog.show({message: msg})receiveData(eventName: string, json: string){WebSdkClass.context?.eventHub?.emit(eventName, json)}
}
回答: 
鸿蒙原生和h5通信有大概两种方式
1. 通过消息机制推送,类似于前端的postMessage的跨域通信,首先通过原生端的webviewController进行创建通信端口, createMessagePorts, 该方法会创建两个端口,一个用作原生端,一个用作h5端,然后通过webviewController将其中一个端口通过postMessage发送到h5端,h5端用onmessage来接收该端口,并全局缓存,此时,h5端用接收的端口发送消息给原生端,原声端用自己剩余的端口进行onMessage接听消息,此时就可以实现双向通信
2. api调用的形式原生端可以通过javascriptProxy给h5页面注入可用的sdk应用方法集合,在h5完成初始化后,可以直接调用原生的方法,这是h5调用原生原生端也可以直接调用h5端的方法 runJavascript,在这个方法里面传入方法调用传参数就可以
需要注意的点: 如果原生端的sdk方法是个异步方法,在h5端无法及时得到结果,
此时需要再用原生反调h5进行传递结果

坑点
watch不能写在修饰符前面
prop只支持数字、字符串、布尔三种类型

总结:
● Column/Row
● Text/Button/TextInput
● Flex-List-带滚动条-Scroll(不要对子组件的宽和高进行设置,内部只能放一个子组件)
● 条件渲染(if else)/循环渲染(ForEach)
● State修饰符(声明响应式数据)- 驱动UI的更新-只会监听第一层数据

● State组件内状态
● Prop子组件修饰符-4.0 boolean/number/string- 单向数据流
● Link 子组件修饰符-双向数据流,所有类型都支持- 必须通过$前缀-(循环数据就没有办法传入)
● Provide和Consume 双向数据流-所有结构均支持
● Watch 可以监听State Link Prop ObjectLink的数据变化
● Observed和ObjectLink

● Link-双向
● Prop-单向
● Observed 和 ObjectLink- (肯定不能用在entry修饰的组件中)
● LocalStorage(UIAbility)-AppStorage-PersionStorage(写入磁盘-不能每次都直接运行)
PersionStorage来声明一下属性就可以保证该属性会被写入缓存
● StorageProp-StorageLink
● Http
● 嵌套更新数据的方式-Next


http://www.ppmy.cn/devtools/135211.html

相关文章

RSA加密方式及常见攻击手法

RSA&#xff1a; RSA加密操作流程&#xff1a; 第一步&#xff1a;选取一对不相等且足够大的质数&#xff0c;记做p和q&#xff1b; 第二步&#xff1a;计算p和q的乘积n&#xff1b;npq; 第三步&#xff1a;计算欧拉函数&#xff1a;phi(n)(p-1)(q-1) 第四步&#xff1a;选…

贴代码框架PasteForm特性介绍之datetime,daterange

简介 PasteForm是贴代码推出的 “新一代CRUD” &#xff0c;基于ABPvNext&#xff0c;目的是通过对Dto的特性的标注&#xff0c;从而实现管理端的统一UI&#xff0c;借助于配套的PasteBuilder代码生成器&#xff0c;你可以快速的为自己的项目构建后台管理端&#xff01;目前管…

2021 年 3 月青少年软编等考 C 语言三级真题解析

目录 T1. 找和为 K 的两个元素思路分析 T2. Minecraft思路分析 T3. 踩方格思路分析 T4. 苹果消消乐思路分析 T5. 流感传染思路分析 T1. 找和为 K 的两个元素 在一个长度为 n ( n < 1000 ) n\ (n < 1000) n (n<1000) 的整数序列中&#xff0c;判断是否存在某两个元素…

【机器学习】从马尔可夫链到CRF:全方位解析序列建模的核心技术

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

软件测试之缺陷管理

一、软件缺陷的基本概念 1、软件缺陷的基本概念主要分为&#xff1a;缺陷、故障、失效这三种。 &#xff08;1&#xff09;缺陷&#xff08;defect&#xff09;&#xff1a;存在于软件之中的偏差&#xff0c;可被激活&#xff0c;以静态的形式存在于软件内部&#xff0c;相当…

Hive的map/struct/array怎么通过insert插入数据

废话 hive在高级使用语法时&#xff0c;会遇到map/struct/array等操作。但是我们只需想测试某几种数据&#xff0c;不想搞得麻烦通过定义数据文件&#xff0c;然后创建数据结构&#xff0c;再导入这一系列流程&#xff0c;就为验证一个感觉很简单的问题。于是想简化这个步骤&am…

Spark_写ORALCE:ORA-01426 numeric overflow 问题解决

问题 是这样的&#xff0c;20241118&#xff0c;我spark程序写Oracle时候&#xff0c;关联完HBase数据后&#xff0c;在写入ORACLE中&#xff0c;遇到了这个bug&#xff0c; 数据入到一半&#xff0c;每次都报错ORA-01426 numeric overflow&#xff0c;具体呢&#xff0c;也不告…

【云原生后端开发流程及详细教程】

云原生后端开发流程及详细教程 一、前期规划二、开发阶段三、部署阶段四、监控与优化一、前期规划 需求分析 明确后端要实现的功能。例如,构建一个简单的待办事项(To - Do)列表应用的后端,需要支持用户创建、读取、更新和删除(CRUD)待办事项。功能包括用户注册/登录、任务…