HarmonyOS知识点

ops/2024/11/19 16:57:29/

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边框线
.border({width: 1,color: {left: Color.White,right: Color.White,top: Color.White,bottom: Color.Black},
})
// 渐变色
.linearGradient({angle: '94deg',colors: [[$r('app.color.color_FF852E'), 0], [$r('app.color.color_FF5F2E'), 99]]
})
// 最大宽 高
.constraintSize({maxWidth: '',maxHeight: ''
})
// 实现软键盘弹出后,整体布局不变
.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/ops/135026.html

相关文章

CertiK安全调研报告:Web3.0桌面钱包的初步安全评估

桌面钱包在Web3.0生态系统中扮演着关键角色&#xff0c;它们为用户在去中心化网络中安全地管理数字资产提供了可靠的解决方案。Cointelegraph的报告[1]指出&#xff0c;据Bitfinex交易所的分析师观察显示&#xff0c;截至2023年12月1日&#xff0c;全球数字货币持有者的数量显著…

pom中无法下载下来的类外部引用只给一个jar的时候

比如jar在桌面上放着,操作步骤如下&#xff1a; 选择桌面&#xff0c;输入cmd ,执行mvn install:install-file -DgroupIdcom -DartifactIdaspose-words -Dversion15.8.0 -Dpackagingjar -Dclassifierjdk11 -Dfilejar包名称 即可把jar包引入成功。

《译文》2024年11月数维杯国际大学生数学建模挑战赛题目

# 赛题正式发布 2024年第十届数维杯国际大学生数学建模挑战赛顺利开赛&#xff0c;竞赛开始时间为北京时间2024年11月15日09:00至北京时间2024年11月19日09:00&#xff0c;共计4天&#xff0c;竞赛题目正式发布&#xff0c;快来一起围观&#xff0c;你认为今年的哪个题目更具有…

037集——JoinEntities连接多段线polyline和圆弧arc(CAD—C#二次开发入门)

如图&#xff1a;最终效果 polyline连接&#xff1a; 代码如下&#xff1a; public void joinentities() {Curve pLine Z.db.SelectEntities<Curve>().First().Clone() as Curve;pLine.ChangeEntityColor(1);Curve pLine1 Z.db.SelectEntities<Curve>().First()…

html 图片转svg 并使用svg路径来裁剪html元素

1.png转svg 工具地址: Vectorizer – 免费图像矢量化 打开svg图片,复制其中的path中的d标签的路径 查看生成的svg路径是否正确 在线SVG路径预览工具 - UU在线工具 2.在html中使用svg路径 <svg xmlns"http://www.w3.org/2000/svg" width"318px" height…

FFmpeg源码:avio_read_partial函数分析

AVIOContext结构体和其相关的函数分析&#xff1a; FFmpeg源码&#xff1a;avio_r8、avio_rl16、avio_rl24、avio_rl32、avio_rl64函数分析 FFmpeg源码&#xff1a;read_packet_wrapper、fill_buffer函数分析 FFmpeg源码&#xff1a;avio_read函数分析 FFmpeg源码&#xff…

ORA-01461: 仅能绑定要插入 LONG 列的 LONG 值。ojdbc8版本23.2.0.0驱动BUG【已解决】

问题描述 JDK8使用ojdbc8驱动操作oracle11g数据库&#xff0c;使用JDBC复用 PreparedStatement 对象执行Insert操作时&#xff0c;报错java.sql.SQLException: ORA-01461: 仅能绑定要插入 LONG 列的 LONG 值。&#xff0c;经测试发现&#xff0c;是预编译对象某个占位符号被赋…

大型语言模型综述 A Survey of Large Language Models

文章源自 2303.18223 (arxiv.org) 如有侵权&#xff0c;请通知下线 这是一篇关于大语言模型&#xff08;LLMs&#xff09;的综述论文&#xff0c;主要介绍了 LLMs 的发展历程、技术架构、训练方法、应用领域以及面临的挑战等方面&#xff0c;具体内容如下&#xff1a; 摘要…