状态管理
在声明式UI中,状态驱动视图更新:
状态(State):指驱动视图更新的数据(被装饰器标记的变量)
视图(View):基于UI描述渲染得到用户界面
@State装饰器
1.@State装饰器标记的变量必须初始化,不能为空值2.@State支持Object、class、string、number、boolean、enum类型以及这些类型的数组3.嵌套类型(比如Person类中嵌套Person)以及数组中的对象的属性变更无法触发视图更新
数组添加元素:push.删除元素:splice(起始位置,删除个数)
slice 是字符串的一个方法,用于提取字符串的某个部分,并返回一个新的字符串,不会改变原字符串
@Prop,@Link,@Consume,@Provide装饰器
@Prop,@Link
父子组件之间需要数据同步时使用@Prop,@Link
父组件中的变量使用@State装饰.子组件中对应变量使用@Prop装饰.当父组件对@State装饰的变量进行修改时会立刻把数据传递给子组件.其实是把父组件变量的数据拷贝了一份给了儿子.但子组件对@Prop装饰的变量进行修改时不会把数据传递给父组件.即对拷贝的这份不论怎么修改都不会影响原数据.
父组件中的变量使用@State装饰.子组件中对应变量使用@Link装饰.父组件对@State装饰的变量进行修改时会立刻把数据传递给子组件,子组件同理.其实父亲和儿子访问的是同一个变量.
Link修饰的变量在初始化时需要加$:
TaskList({finishTask:totalTask})
允许装饰的变量类型:
Prop:1.string、number、boolean、enum类型
2.当父组件装饰的是对象类型,子组件装饰对象的属性即可·但父组件装饰的是数组类型时,子组件装饰数组中的元素就不可以了
3.@Prop装饰的变量不允许初始化
Link:1.父子类型必须一致:string、number、boolean、enum,object,class,以及他们的数组
2.数组中元素增、删、替换会引起刷新 3.嵌套类型(比如Person类中嵌套Person)以及数组中的对象的属性变更无法触发视图更新4.@Link装饰的变量不允许初始化
注:build函数中只能有一个根元素
@Consume(子),@Provide(父)
@Consume,@Provide可以跨组件(也可以不跨,即代替@Prop,@Link)提供双向同步,这种机制不需要传参
@ObjectLink和@Observed
@ObjectLink和@Observed装饰器用于在涉及嵌套对象或数组元素为对象的场景中进行双向数据同步
使用:给嵌套对象对应的类(里面的person)加@Observed.给里面的对象加@ObjectLink
@Observed @Entry class Person { @Component name: string struct Parent { age: number @state p: Person = gf: Person new Person('Jack', 21, new Person('Rose',18)) constructor(name:string,age: number, build() { gf?: Person) { Column( ) { this.name = name Text(${this p.gf.name} : ${this.p.gf.age},
) this.age = age .onClick(() => this.p.gf.age++) this.gf = gf
@Watch
用于监听状态变量的变化,语法结构为:
@State @Watch("onChanged") count : number = 0
方法传递bind(this)
方法在传递时,为了不让this改变,在传递方法时,给方法调bind(this),即把当前父组件的this绑定在这个函数上,那么这个函数内部的this就是当前这个父组件.
ListItem(){ TaskItem({item: item,onTaskChange: this.handleTaskChange.bind(this)}) }
在子组件中要控制父组件元素的弹出:在子组件声明函数,在父组件调用时覆盖这个声明
ListItem侧滑效果:给List加.swipeAction
网络连接
三种网络连接方式:HTTP数据请求,WebSocket连接,Socket连接
HTTP数据请求(常用)
由客户端向服务端发起的单向的连接方式
应用内部很多数据不在应用中而保存在服务端,客户端发起请求->服务端返回响应.
网络请求有一定的延迟.request方法执行完但不一定拿到结果.异步任务都会返回一个Promise:存放未来返回的结果.给Promise添加回调函数.将来异步事件处理完成,成功走成功回调,失败走失败回调
发送请求步骤:
1.导入http模块
import http from '@ohos.net.http'
2.使用http模块发送请求,处理响应
2.1.创建一个http的请求对象,不可复用,下次再发请求时要创建新的http的请求对象
let httpRequest = http.createHttp()
2.2.发起网络请求
httpRequest.request( 'http://localhost:3000/users, // 请求URL路径 {// 请求选项HttpRequestOptions method: http.RequestMethod.GET, extraData: {'paraml': 'valuel'} // k1=v1&k2=v2 //还有很多,不止这两个 } ) //Promise:存放未来会完成的结果
2.3.处理响应结果
.then((resp: http.HttpResponse) => {//说明请求发送成功,但在服务端处理可能出问题 if(resp.responseCode===200){//才说明真的请求成功 //请求成功 } }) .catch((err: Error) => { //请求失败 });
Stage模型
基本概念和应用配置文件
模块是应用的基本功能单元,里面包含源代码,资源,配置文件等.一个应用->多个模块(但只含一个入口类型模块),一个模块->多个Ability.每一个模块可以独立编译和运行.模块分为Ability Module和Library Module(共享,依赖类型的模块).Ability Module可以引用Library Module.Ability Module将被编译成HAP文件.Library Module将被编译成HSP文件.HAP在运行过程中可以引用和依赖HSP.多个HAP合并在一起称为Bundle.每个Bundle都有自己的名字BundleName,他是整个应用的唯一标识.采用多HAP的打包模式:①降低各模块之间的耦合,每一个模块可以独立编译和运行②下载安装应用时可选择性安装,降低安装所占体积.HAP运行时为了展示他的界面和能力,怎么做呢?创建一个AbilityStage实例.在舞台上创建Ability.UIAbility展示组件时先持有WindowStage,进一步持有Window和ArkUIPage.Ability的常见类型:UIAbility和ExtensionAbility.
AppScope目录下的app.json5里面是应用的全局配置信息.其中的icon和name是应用列表的的图标和名称.每个模块内有一个module.json5文件,它是当前模块的配置信息.其中type的值有:entry,feature,shared.其中abilities中的entryability中的icon和label就是桌面图标和名称.
Stage模型把Ability和窗口Window分隔开了.在开发跨设备应用时,就可以针对不同的设备对他的窗口进行单独的裁剪.
应用运行的过程就是一个个UIAbility创建,切换到最终销毁的过程.
在任务列表中,每一个任务代表一个独立的Ability实例
UIAbility生命周期
在桌面点击应用图标,AbilityStage->创建EntryAbility:Create->把EntryAbility放到台前:Foreground<=>(其他Ability切到前台了)放到台后:Background->销毁:Destroy
UIAbility对应的生命周期钩子在entryability类中
每一个Ability都有自己的生命周期,这个生命周期定义在这个Ability的类中.entryability的生命周期定义在entryability类中
页面和组件的生命周期
多个组件构成一个页面.一个页面要加载,首先要加载的就是它的入口组件.一个组件要加载要先把组件对应的实例创建出来(创建组件实例).组件对应的页面是靠build函数绘制的(执行build函数)在入口组件中用到的每个子组件,依然需要先创建组件实例再执行build函数,入口组件build函数执行完,页面才算绘制完(展示页面).随后页面可能会返回或跳转从而页面隐藏,页面中的组件有没有被销毁需要看这个页面有没有销毁(pushurl和replaceurl)页面销毁了组件也就销毁了,其中的子组件也就销毁了(销毁组件).在这个过程中.Stage模型提供了一些生命周期钩子.
aboutToAppear:在创建组件实例之后,执行build函数之前调用.一般进行数据初始化和准备工作,build函数执行时就可以利用这些数据进行渲染.
aboutToDisappear:在组件销毁之前调用.一般进行数据保存或资源释放
onPageshow:页面展示后
onBackpress:点击返回时
onPageHide:隐藏页面前
注:页面如果在,其中的子组件不一定也在(如父组件中通过判断来渲染子组件,当条件从满足变为不满足时子组件销毁)
子组件中不会触发与page有关的生命周期钩子.
for循环渲染特性:数组中元素发生变更时,会检查数组中的元素,对发生变更的进行重新渲染,就会把以前所有的元素销毁,再次渲染.Foreach的第三个参数是给每一个元素加一个唯一标识,只要唯一标识不变就认为这个元素没变.
UIAbility的启动模式
Singleton(默认模式)
UIAbility不管启动多少次,都只存在唯一实例
Standard
每次启动UIAbility,都会创建一个实例,多实例并存
multiton模式每次启动UIAbility,都会创建一个实例但旧实例会被移除
Specified
启动UIAbility时需要为UIAbility实例指定Key,存在Key相同的实例直接被拉起.不存在则创建新的实例.
//1.第三种模式则存在在一个ability中唤醒另一个ability的场景,当前UIAbility需要调用startAbility方法拉起目标UIAbility
调取getContext方法获取UIAbilityContext上下文对象:
context=getContext(this) as common.UIAbilityContext
拿这个对象调用startAbility方法从而拉起目标Ability:
this.context.startAbility(want)
拉起哪个Ability呢?
let want:Want={ deviceld: ''// deviceId为空表示本设备 bundleName: 'com.example.myapplication', abilityName: 'DocumentAbility', moduleName: 'entry'//这个ability在哪个模块,moduleName非必选 parameters: { // getInstanceKey:自定义方法,生成目标UIAbility实例的key instanceKey: this.getInstanceKey() } }
拉起的Ability要在AbilityStage上展示.
// 2.在AbilityStage的生命周期回调中为目标UIAbility实例生成key
export default class MyAbilityStage extends AbilityStage{ onAcceptwant(want: Want): string { // 判断当前要拉取的是否是DocumentAbility if(want.abilityName === 'DocumentAbility'){ //根据参数中的instanceKey参数拼接生成一个key值并返回 return`DocAbility_${want.parameters.instanceKey}` } //拿到Key再拼接你想拼的信息 return''; } }
参数中传的KEY被AbilityStage接收,AbilityStage根据接收到的KEY选择具体的Ability
// 3.在module.json5配置文件中,通过srcEntry参数指定AbilityStage路径
{ "module": { "name": "entry", "type": "entry", "srcEntry": "./ets/myabilitystage/MyAbilityStage.ts", ... } }