一、@BuilderParam装饰器
当开发者创建了自定义组件,并想对该组件添加特定功能时,例如在自定义组件中添加一个点击跳转操作。若直接在组件内嵌入事件方法,将会导致所有引入该自定义组件的地方均增加了该功能。为解决此问题,ArkUI引入了@BuilderParam装饰器,@BuilderParam用来装饰指@Builder方法的变量,开发者可在初始化自定义组件时对此属性进行赋值,为自定义组件增加特定的功能。该装饰器用于声明任意UI描述的一个元素,类似slot占位符。
TypeScript
@Entry
@Component
struct Page_builderParam {
@State message: string = 'Hello World'
title: string = ''
@State isShow: boolean = true;
@Builder
left() {
Row() {
Button("大房子").onClick(()=>{
this.isShow=!this.isShow
console.log(this.isShow+"ddd")
})
}
}
@Builder
right() {
Row() {
Button("好车子")
}
}
@Builder
list1(){
Column(){
ForEach(["住宅","写字楼","商铺"],item=>{
Text(item).fontColor(Color.Green).fontSize(19)
})
}
}
build() {
Row() {
Column() {
Nav({ title: "金山", left: this.left.bind(this), right: this.right })
if(this.isShow){
list({list1:this.list1})
}
}
.width('100%')
}
.height('100%')
}
}
@Component
struct Nav {
title: string = ""
@BuilderParam left: () => void
@BuilderParam right: () => void
build() {
Row() {
this.left()
Text(this.title)
this.right()
}.width("100%").justifyContent(FlexAlign.SpaceBetween)
}
}
@Component
struct list {
title: string = ""
@BuilderParam list1:()=>void
build() {
Row() {
this.list1()
}
.width("100%")
.height(89)
.margin({ top: 10 })
.justifyContent(FlexAlign.SpaceBetween)
.backgroundColor(Color.Gray)
}
}
二、生命周期
页面生命周期:
即被@Entry装饰的组件生命周期。提供以下生命周期接口:
onPageShow: 页面每次显示时触发一次,包括路由过程、应用进入前台等场景,仅@Entry装饰的自定义组件生效。
onPageHide: 页面每次隐藏时触发一次,包括路由过程、应用进入前后台等场景,仅@Entry装饰的自定义组件生效。
onBackPress:当用户点击返回按时触发,仅@Entry装饰的自定义组件生效。
组件生命周期
即一般用@Component装饰的自定义组件的生命周期,提供以下生命周期接口:
aboutToAppear: 组件即将出现时回调该接口,具体时机为在创建自定义组件的新实例后,在执行其build()函数之前执行。
aboutToDisappear: 在自定义组件析构销毁之前执行。不允许在aboutToDisappear函数中改变状态变量,特别是@Link变量的修改可能会导致应用程序行为不稳定。
简单举例说明:
TypeScript
@Entry
@Component
struct PageLife {
@State message: string = 'Hello World'
@State isShow: boolean = true;
// 页面准备-可以网络请求
aboutToAppear() {
console.log("aboutToAppear")
}
// 页面显示
onPageShow() {
console.log("onPageShow")
}
// 页面离开
onPageHide() {
console.log("onPageHide")
}
// 返回按钮
onBackPress() {
console.log("onBackPress")
}
// 页面销毁
aboutToDisappear() {
console.log("aboutToDisappear")
}
build() {
Row() {
Column() {
Text("爆炸现场")
.fontSize(50)
.fontWeight(FontWeight.Bold)
if (this.isShow) {
Boob({isShow:$isShow})
} else {
Button("已爆炸")
}
}
.width('100%')
}
.height('100%')
}
}
@Component
struct Boob {
@Link isShow:boolean
@State count: number = 10
timer: number = 0
aboutToAppear() {
this.timer=setInterval(() => {
this.count--
// this.isShow为false时,该组件销毁====》调用aboutToDisappear方法。
if(this.count===0){
this.isShow=false
}
console.log(this.count+"")
}, 1000)
}
aboutToDisappear() {
clearInterval(this.timer)
}
build() {
Column() {
Button("倒计时")
Text(this.count+" S").fontSize(20)
}
}
}
三、页面路由
页面路由指在应用程序中实现不同页面之间的跳转和数据传递。HarmonyOs提供了Router模块,通过不同的ur地址,可以方便地进行页面路由,轻松地访问不同的页面。
Router模块提供了两种跳转模式,分别是router.pushUrl()和router.replaceUrl()。这两种模式决定了目标页是否会替换当前页。
router.pushUrl(): 目标页不会替换当前页,而是压入页面栈。这样可以保留当前页的状态,并且可以通过返回键或者调用router.back()方法返回到当前页。
router.replaceUrl(): 目标页会替换当前页,并销毁当前页。这样可以释放当前页的资源,并且无法返回到当前页。
并且Router模块提供了两种实例模式,分别是Standard和Single。这两种模式决定了目标url是否会对应多个实例
Standard: 标准模式,也是默认情况下的实例模式。每次调用该方法都会新建一个目标页,并压入栈顶。
Single: 单例模式。即如果目标页的url在页面栈中已经存在同ur页面,则离栈顶最近的同url页面会被移动到栈顶,并重新加载,如果目标页的url在页面栈中不存在同url页面,则按照标准模式跳转。
router.pushUrl()------>Standard A跳转到B,栈中有B,还是新建B,A压入栈中,B在A上。
router.pushUrl()------>Single A跳转到B,栈中有B,不新建B,A压入栈中,已有B提至A上。
router.replaceUrl()------>Standard A跳转到B,栈中有B,还是新建B,销毁A。B置于栈顶。
router.replaceUrl()------>Single A跳转到B,栈中有B,不新建B,销毁A,已有B提至栈顶。
TypeScript
import router from '@ohos.router'
@Entry
@Component
struct PageRouter {
@State message: string = '努力方向'
@State list: Object[] = [{
id: 1,
name: "房子"
}, { id: 2, name: "车子" }, { id: 3, name: "金条" }]
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
List() {
ForEach(this.list, item => {
ListItem() {
Text(item.name).fontSize(40).margin({top:10}).fontColor(Color.Orange)
}.width('100%').onClick(()=>{
router.pushUrl({
url:'pages/PageRouterDetail',
params:{
id:item.id,
name:item.name
}
},router.RouterMode.Standard)
})
})
}
}
.width('100%')
}
.height('100%')
}
onPageShow(){
const param=router.getParams();
console.log("PageRouter-onPageShow",JSON.stringify(param))
}
}
TypeScript
import router from '@ohos.router'
@Entry
@Component
struct PageRouterDetail {
@State message: string = '拿到'
name: string
aboutToAppear() {
const param = router.getParams()
const jsp=JSON.stringify(param)
console.log("D_aboutToAppear", jsp)
this.name=JSON.parse(jsp).name
console.log("D_aboutToAppear", this.name )
}
build() {
Row() {
Column() {
Text(this.name)
.fontSize(50)
.fontWeight(FontWeight.Bold)
Button("返回").onClick(() => {
this.onReturn1()
})
}
.width('100%')
}
.height('100%')
}
onReturn1() {
router.showAlertBeforeBackPage({
message:'确定要返回吗?'
})
router.back({
url:"pages/PageRouter",
params:{
id:4,
name:"我发财了"
}
})
}
}
四、程序入口
UIAbility是一种包含用户界面的应用组件,主要用于和用户进行交互。UIAbility也是系统调度的单元,为应用提供窗口在其中绘制界面。
每一个UIAbility实例,都对应于一个最近任务列表中的任务。
UIAbility生命周期
UIAbility是在module.json5里面配置的。
TypeScript
import common from '@ohos.app.ability.common'
@Entry
@Component
struct PageEntry {
@State message: string = 'Hello World'
private context =getContext(this) as common.UIAbilityContext
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
Button("跳转ability").onClick(()=>{
let want={
deviceId:"",
bundleName:getContext(this.context).applicationInfo.name,//获得包名
abilityName:"MoneyAbility",
parameters:{
name:"随便拿,都是你的了"
}
}
this.context.startAbility(want)
})
}
.width('100%')
}
.height('100%')
}
}
TypeScript
@Entry
@Component
struct PageMoney {
@State message: string = '金子银子随便拿'
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
}
.width('100%')
}
.height('100%')
}
}
TypeScript
{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": [
"phone",
"tablet"
],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages",
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ts",
"description": "$string:EntryAbility_desc",
"icon": "$media:icon",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:icon",
"startWindowBackground": "$color:start_window_background",
"exported": true,
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"action.system.home"
]
}
]
},
{
"name": "MoneyAbility",
"srcEntry": "./ets/MoneyAbility/MoneyAbility.ts",
"description": "$string:EntryAbility_desc",
"icon": "$media:icon",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:icon",
"startWindowBackground": "$color:start_window_background",
"exported": true
}
]
}
}
TypeScript
import UIAbility from '@ohos.app.ability.UIAbility';
import hilog from '@ohos.hilog';
import window from '@ohos.window';
export default class MoneyAbility extends UIAbility {
onCreate(want, launchParam) {
console.log("MoneyAbility--",want?.parameters?.name)
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
}
onDestroy() {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
}
onWindowStageCreate(windowStage: window.WindowStage) {
// Main window is created, set main page for this ability
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
AppStorage.SetOrCreate("name","房子")
windowStage.loadContent('pages/PageMoney',(err, data) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
}
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
});
}
onWindowStageDestroy() {
// Main window is destroyed, release UI related resources
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
}
onForeground() {
// Ability has brought to foreground
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
}
onBackground() {
// Ability has back to background
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
}
}