区别:ArkTS 是语言,ArkUI 是框架
开发工具:DevEco Studio
一个应用中往往包含多个页面
一个页面就是一个结构描述
struct
用于描述一个自定义组件,名称与文件名相同,使用驼峰命名法一个组件中必须包含以下内容:
build()
,用于构建组件 UI 界面,其中:
@Component
/@CustomDialog
,组件装饰器/自定义对话框装饰器@Entry
,该装饰器可以将组件作为单独页面在 Preview 中进行预览
@State
,该装饰器作用于组件的内部变量,当变量修改后(数据监视),页面会自动重新渲染;声明时必须初始化
组件可以不断进行嵌套
build() {
Row() {
Column() {
Row() {
// ...
}
}
}
}
组件是一个封装好的对象,包括属性(样式)、方法(事件)
build() {
Column() {
Text("Item 1")
Text("Item 2")
Text("Item 3")
}.width(300)
}
300
是虚拟像素,根据屏幕换算举例:
@Entry
@Component
struct Index {
@State message: string = 'Hello World'
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
}
.width('100%')
}
.height('100%')
}
}
fontSize
:字号
Text("Hello, world!").fontSize(60)
fontColor
:文本颜色
Text("Hello, world!").fontColor(Color.Red)
// 或
Text("Hello, world!").fontColor("#f00")
fontWeight
:字重
Text("Hello, world!").fontWeight(FontWeight.Bold)
// 或
Text("Hello, world!").fontWeight(800)
fontStyle
:字样
Text("Hello, world!").fontStyle(FontStyle.Normal) // 常规
Text("Hello, world!").fontStyle(FontStyle.Italic) // 斜体
fontFamily
:字体
textAlign
:对齐方向
Text("Hello, world!")
.width("100%")
.textAlign(TextAlign.Start)
lineHeight
:行高
Text("Hello, world!").lineHeight(300)
decoration
:划线
Text("Hello, world!").decoration({type: TextDecorationType.Underline}) // 下划线
Text("Hello, world!").decoration({type: TextDecorationType.Overline}) // 上划线
Text("Hello, world!").decoration({type: TextDecorationType.LineThrough}) // 删除线
backgroundColor
:背景颜色backgroundImage
:背景图片width
:宽度
height
:高度
padding
:内边距
Text("Hello, world!").padding({top:10})
border
:边框
Text("Hello, world!").border({style: BorderStyle.Solid, color: Color.Red, radius: 50})
margin
:外边距
Text("Hello, world!").margin(10)
列间距(行间距同理)
Column({space: 16}) {}
事件三要素:事件源、事件类型、事件处理
(参数列表) => 函数体
,方便访问组件内其他属性与方法Button("Click").onClick(()=>{
console.log("Log")
})
可以使用 bind
将 this
绑定到普通函数中
@Entry
@Component
struct Index {
text: string = "This is a piece of text."
handle() {
console.log(this.text);
}
build() {
Column() {
Button("Click").onClick(this.handle.bind(this))
}
.width("100%")
.height("100%")
}
}
语法:Text(content?: string | Resource)
长文本最大行数与省略显示
Text("This is a long long sentence.")
.width(100)
.maxLines(1)
.textOverflow({overflow:TextOverflow.Ellipsis})
国际化
src/main/resources/base/element/string.json
{
"string": [
{
"name": "username",
"value": "用户名"
},
{
"name": "password",
"value": "密码"
}
]
}
src/main/resources/en_US/element/string.json
{
"string": [
{
"name": "username",
"value": "username"
},
{
"name": "password",
"value": "password"
}
]
}
src/main/resources/zh_CN/element/string.json
{
"string": [
{
"name": "username",
"value": "用户名"
},
{
"name": "password",
"value": "密码"
}
]
}
Index.ets
Column() {
Row() {
Text($r('app.string.username'))
.fontSize(50)
}
Row() {
Text($r('app.string.password'))
.fontSize(50)
}
}
.width('100%')
.height('100%')
语法:TextInput(value?:{placeholder?: ResourceStr, text?: ResourceStr, controller?: TextInputController})
登录表单
Column({space: 20}) {
Row() {
Text($r('app.string.username'))
.fontSize(22)
.width("20%")
TextInput({placeholder: "输入账号"})
.width("70%")
}
Row() {
Text($r('app.string.password'))
.fontSize(22)
.width("20%")
TextInput({placeholder: "输入密码"})
.width("70%")
.type(InputType.Password)
}
}
语法:Button(options?: {type?: ButtonType, stateEffect?: boolean})
登录表单按钮组
Row({ space: 20 }) {
Button($r('app.string.login'))
.fontSize(22)
Button($r('app.string.reset'))
.fontSize(22)
.type(ButtonType.Normal)
}
完善登录页面
@Entry
@Component
struct Index {
@State username: string = ""
@State password: string = ""
build() {
Column({space: 20}) {
Row() {
Text("登录 Login")
}
Row() {
Text($r('app.string.username'))
TextInput({placeholder: "输入账号", text: this.username})
.onChange(content => this.username = content)
}
Row() {
Text($r('app.string.password'))
TextInput({placeholder: "输入密码", text: this.password})
.type(InputType.Password)
.onChange(content => this.password = content)
}
Row({ space: 20 }) {
Button($r('app.string.login'))
.onClick(() => {
console.log("username:" + this.username)
console.log("password:" + this.password)
})
Button($r('app.string.reset'))
.onClick(() => {
this.username = ""
this.password = ""
})
}
}
}
}
语法:Blank(min?: number | string)
占据父容器中剩余空间
调整表单对齐
Column({ space: 20 }) {
Row() {
Text("Item1")
Blank()
TextInput()
.width(200)
}
.width("80%")
Row() {
Text("Item2")
Blank()
TextInput()
.width(200)
}
.width("80%")
}
.width('100%')
.height('100%')
语法:Image(src: string | PixelMap | Resource)
可以渲染与展示本地图片和网络图片
Column({ space: 20 }) {
Image($r('app.media.logo'))
.width("50%")
Image("https://developer.huawei.com/allianceCmsResource/resource/HUAWEI_Developer_VUE/images/HW-LOGO.svg")
.width("50%")
}
.width('100%')
.height('100%')
语法:Slider(options?: {value?: number, min?: number, max?: number, step?: number, style?: SliderStyle, direction?: Axis, reverse?: boolean})
举例
Column({ space: 20 }) {
Slider({
min: 0, // 最小值
max: 20, // 最大值
value: this.value, // 当前值
step: 2, // 步长
style: SliderStyle.InSet // 样式
})
.trackColor(Color.Red) // 轨道颜色
.selectedColor(Color.Pink) // 选中颜色
.trackThickness(9) // 轨道厚度
.onChange(value => this.value = value)
Text(this.value.toString())
}
.width('100%')
.height('100%')
.backgroundColor("#ccc")
图片尺寸设置案例:
@Entry
@Component
struct Index {
@State widthValue:number = 100
minWidth:number = 50
maxWidth:number = 340
build() {
Column({ space: 20 }) {
Text("图片尺寸设置")
Row() {
Image($r("app.media.image"))
.width(this.widthValue)
}
Row() {
Text("图片宽度 ")
TextInput({ text: parseInt(this.widthValue.toFixed(0)).toString() })
.onChange(value => this.widthValue = widthValue)
}
Row() {
Button("缩小").onClick(() => this.widthValue -= 1)
Button("放大").onClick(() => this.widthValue += 1)
}
Slider({
min: this.minWidth,
max: this.maxWidth,
value: this.widthValue,
step: 1
})
.onChange(value => this.widthValue = value)
}
}
}
语法:List(value?:{space?: number | string, initialIndex?: number, scroller?: Scroller})
其子组件只能是 ListItem(value?: string)
或 ListItemGroup(options?: {header?: CustomBuilder, footer?: CustomBuilder, space?: number | string})
ListItem
中可以使用其他组件ListItem
组件的 swipeAction()
支持侧滑手势,其中传入组件用于设置侧滑的内容举例 1:电商平台商品列表
import router from '@ohos.router'
interface IProduct {
id: number,
imageURL: string,
name: string,
price: number,
discounted?: number
}
@Entry
@Component
struct Page {
titleBgColor: string = "#fafafa"
contentBgColor: string = "#eee"
products: Array<IProduct> = [
{
id: 1,
imageURL: "",
name: "Product 1",
price: 7599,
discounted: 500
}
]
build() {
Column() {
Row() {
Button() {
Image($r('app.media.arrow'))
}
.onClick(() => {
router.back()
})
Text("商品列表")
Blank()
Button() {
Image($r('app.media.refresh'))
}
.onClick(() => {
console.log("Refresh")
})
}
.backgroundColor(this.titleBgColor)
List({ space: 20 }) {
ForEach(this.products, (item) => {
ListItem() {
Row() {
Image(item.imageURL)
Column({ space: 10 }) {
Text(item.name)
if(item.discounted) {
Text("价格:¥" + item.price)
.fontColor("#aaa")
.decoration({ type: TextDecorationType.LineThrough})
Text("折后价:¥" + (item.price - item.discounted))
Text("优惠:¥" + item.discounted)
} else {
Text("价格:¥" + item.price)
}
}
.layoutWeight(1)
}
}
.border({ width: 2, style: BorderStyle.Solid, color: this.contentBgColor, radius: 20 })
})
}
}
.backgroundColor(this.contentBgColor)
}
}
举例 2:通讯录
interface IAddressItem {
group: string,
contactList: string[]
}
@Entry
@Component
struct Index {
addressBook: IAddressItem[] = [
{
group: "家人",
contactList: ["张三", "李四"]
},
{
group: "朋友",
contactList: ["王五", "赵六"]
},
{
group: "同事",
contactList: ["田七"]
}
]
@Builder
groupHeader(group: string) {
Text(group)
.fontSize(30)
.fontWeight(FontWeight.Bold)
}
build() {
Column() {
Text("通讯录")
.fontSize(50)
.fontWeight(FontWeight.Bolder)
List({ space: 20 }) {
ForEach(this.addressBook, (item:IAddressItem) => {
ListItemGroup({ header: this.groupHeader(item.group) })
ForEach(item.contactList, (item:string) => {
ListItem() {
Text(item)
.fontSize(20)
}
})
})
}
}
.width("100%")
.height('100%')
.padding({ left: 10, right: 10 })
}
}
构建自定义对话框组件
@CustomDialog
struct MyDialog {
controller: CustomDialogController
build() {
Column() {
Text("自定义对话框")
Button("关闭对话框")
.onClick(() => {
this.controller.close()
})
}
}
}
将对话框组件注册到页面中
@Entry
@Component
struct Index {
controller: CustomDialogController = new CustomDialogController({
builder: MyDialog({})
})
}
绑定点击事件触发对话框
build() {
Column() {
Button("开启对话框")
.onClick(() => {
this.controller.open()
})
}
.width('100%')
.height('100%')
}
语法:Tabs(value?: {barPosition?: BarPosition, index?: number, controller?: TabsController})
举例:
@Component
struct AComponent {
build() {
Text("A 组件内容")
}
}
@Component
struct BComponent {
build() {
Text("B 组件内容")
}
}
@Component
struct CComponent {
build() {
Text("C 组件内容")
}
}
@Entry
@Component
struct Index {
@State currentIndex: number = 0
@Builder
customTabBarContent(icon: Resource, title: string, index: number) {
Column({ space: 6 }) {
Image(icon)
.width(20)
.fillColor(this.currentIndex == index ? Color.Green : Color.Black)
Text(title)
.fontSize(16)
.fontColor(this.currentIndex == index ? Color.Green : Color.Black)
}
}
build() {
Column() {
Tabs() {
TabContent() {
AComponent()
}.tabBar(this.customTabBarContent($r("app.media.icon"), "A 组件", 0))
TabContent() {
BComponent()
}.tabBar(this.customTabBarContent($r("app.media.icon"), "B 组件", 1))
TabContent() {
CComponent()
}.tabBar(this.customTabBarContent($r("app.media.icon"), "C 组件", 2))
}
.barPosition(BarPosition.End)
.vertical(false) // 不使用垂直布局
.scrollable(false) // 关闭页面滑动切换
.onChange((index: number) => {
this.currentIndex = index
})
}
.width("100%")
.height("100%")
}
}
构建函数中只能写入组件
语法:
@Builder
函数名(参数) {
函数体;
}
自定义构建函数可以在 build()
中调用
完善电商平台商品列表
@Builder
header() {
Row() {
Button() {
Image($r('app.media.arrow'))
}
.backgroundColor(this.titleBgColor)
.onClick(() => {
router.back()
})
Text("商品列表")
Blank()
Button() {
Image($r('app.media.refresh'))
}
.backgroundColor(this.titleBgColor)
.onClick(() => {
console.log("Refresh")
})
}
.backgroundColor(this.titleBgColor)
}
@Builder
productCard(item:IProduct) {
Row() {
Image(item.imageURL)
Column({ space: 10 }) {
Text(item.name)
if(item.discounted) {
Text("价格:¥" + item.price)
.fontColor("#aaa")
.decoration({ type: TextDecorationType.LineThrough})
Text("折后价:¥" + (item.price - item.discounted))
Text("优惠:¥" + item.discounted)
} else {
Text("价格:¥" + item.price)
}
}
}
}
build() {
Column() {
this.header()
List({ space: 20 }) {
ForEach(this.products,
(item) => {
ListItem() {
this.productCard(item)
}
.border({ width: 2, style: BorderStyle.Solid, color: this.contentBgColor, radius: 20 })
},
(item:IProduct) => {
return item.id.toString()
})
}
}
.backgroundColor(this.contentBgColor)
}
自定义构建函数仅能在当前组件中使用,无法复用到其他组件,因此需要自定义组件
一般写在 ets/components 目录下
完善电商平台商品列表
components/Header.ets
import router from '@ohos.router'
@Component
export default struct Header {
title: string = "Undefined"
titleBgColor: string = "#fafafa"
contentBgColor: string = "#eee"
build() {
Row() {
Button() {
Image($r('app.media.arrow'))
}
.backgroundColor(this.titleBgColor)
.onClick(() => {
router.back()
})
Text(this.title)
Blank()
Button() {
Image($r('app.media.refresh'))
}
.backgroundColor(this.titleBgColor)
.onClick(() => {
console.log("Refresh")
})
}
.backgroundColor(this.titleBgColor)
}
}
entry/Page.ets
build() {
Column() {
Header({ title: "商品列表" })
// ...
}
}
自定义组件使用成本更高,但复用性更强,且其中数据独立
将自定义构建函数作为参数传递到自定义组件
完善电商平台商品列表
components/Header.ets
@Component
export default struct Header {
// ...
@BuilderParam
rightItem: () => void
build() {
Row() {
// ...
this.rightItem()
}
}
}
entry/Page.ets
import Header from '../components/Header'
@Entry
@Component
struct Page {
// ...
@Builder
refreshButton() {
Button() {
Image($r('app.media.refresh'))
}
.onClick(() => {
console.log("Refresh")
})
}
build() {
Column() {
Header({ title: "商品列表", rightItem: this.refreshButton })
// ...
}
}
}
Row
:行布局,从左至右
Column
:列布局,从上至下
justifyContent(FlexAlign.*)
调整对齐,FlexAlign
枚举包括:
Start
:从开始处(默认)Cneter
:居中End
:从结束处SpaceBetween
:均分且开始和结束处不留空间SpaceAround
:均分且间隔比为 \(0.5:1:1:\ \ldots\ :1:0.5\)SpaceEvenly
:均分且间隔空间相同aligmItems
调整对齐,分为:
VerticalAlign
:Row
行布局,其枚举包括:
Top
:从顶部Center
:居中(默认)Bottom
:从底部HorizontalAlign
:Column
列布局,其枚举包括:
Start
:从开始处Center
:居中(默认)End
:从结束处layoutWeight
:填充父容器主轴方向的空闲空间子组件按照顺序依次入栈,后一个子组件覆盖前一个子组件
语法:Stack(value?: { alignContent?: Alignment })
举例:
@Entry
@Component
struct Index {
build() {
Stack({}) {
Column() {}
.width('100%')
.height('100%')
.backgroundColor(Color.Red)
Row() {}
.width("50%")
.height("50%")
.backgroundColor(Color.Green)
}
}
}
由行列分割的单元格所组成,通过指定项目所在的单元格完成布局
语法:Grid(scroller?: Scroller)
类似 List 组件,Grid 要求其中每一项的子组件包含在 GridItem
中
常用属性:
rowsTemplate()
:行模板,设置每行的模板,包括列数与列宽columnsTemplate()
:列模板,设置每列的模板,包括行数与行宽rowsGap()
:行间距columnsGap()
:列间距举例:
@Entry
@Component
struct Page {
array: number[] = [1, 2, 3, 4, 5, 6]
build() {
Grid() {
ForEach(this.array, (item: number) => {
GridItem() {
Text(item.toString())
.width("100%")
.height(100)
.border({
width: 2,
color: Color.Black
})
.fontSize(30)
}
})
}
.width("100%")
.height(220)
.rowsTemplate("1fr 1fr")
.columnsTemplate("1fr 1fr 1fr")
.rowsGap(10)
.columnsGap(10)
}
}
一般数据请求步骤
导入对应模块
import http from '@ohos.net.http';
在方法中,创建 HTTP 请求对象
import http from '@ohos.net.http';
@Component
struct Index {
httpHandler() {
let httpRequest = http.createHttp()
}
// ...
}
调用 request(url, options)
发送请求
httpHandler() {
let httpRequest = http.createHttp()
let promise = httpRequest.request(
"http://example.com",
{
method: http.RequestMethod.GET
}
)
}
url
为请求地址、options
为请求配置request()
方法获取响应结果
httpHandler() {
let httpRequest = http.createHttp()
let promise = httpRequest.request(
"http://example.com",
{
method: http.RequestMethod.GET
}
)
promise.then(
(httpResponse:http.HttpResponse) => {
console.log('Result: ' + httpResponse.result.toString());
}
)
}
默认采用异步方式请求
可以使用 async
与 await
变为同步
Button("登录")
.fontSize(22)
.onClick(async () => {
let httpRequest = http.createHttp()
let response = await httpRequest.request(
`http://10.200.21.163:8080/login?username=${this.username}&password=${this.password}`,
{
method: http.RequestMethod.GET
}
)
console.log(response.result.toString())
})
完善登录页面
Button("登录")
.fontSize(22)
.onClick(() => {
let httpRequest = http.createHttp()
let promise = httpRequest.request(
`http://localhost:8080/login?username=${this.username}&password=${this.password}`,
{
method: http.RequestMethod.GET
}
)
promise.then((httpResponse:http.HttpResponse) => {
console.log(httpResponse.result.toString())
})
})
通过设置关键帧实现动画效果
使用 animateTo(value: AnimateParam, event: () => void): void
方法
value
:对象类型,用于配置动画参数,包括延时、变化曲线等event
:回调函数,用于配置动画关键帧的数据举例:
@Entry
@Component
struct Index {
@State scaleX: number = 0
@State scaleY: number = 0
build() {
Column({ space: 30 }) {
Button("开始动画")
.margin(30)
.onClick(() => {
animateTo({ duration: 500 }, () => {
this.scaleX = 1
this.scaleY = 1
})
})
Row()
.width(200)
.height(200)
.backgroundColor(Color.Red)
.scale({
x: this.scaleX,
y: this.scaleY
})
}
.width("100%")
.height("100%")
}
}
使用 if
、else
和 else if
语句
if
、else if
后跟随的条件语句可以使用状态变量
调整登录按钮
Button() {
Row() {
if(this.isLoading) {
LoadingProgress()
.width(30)
.color(Color.White)
} else {
Text("登录")
.fontSize(22)
.fontColor(Color.White)
}
}
}
使用 ForEach
语句
语法:
ForEach(
arr: Array,
itemGenerator: (item: any, index: number) => void,
keyGenerator?: (item: any, index: number) => string
)
arr
:数组,数组包含多个元素,数组长度决定组件渲染个数itemGenerator
:子组件生成函数,用于生成页面组件,参数分别为数组每项的值与索引keyGenerator
:(可选)键值生成函数,用于指定每项的 id:string
,参数分别为数组每项的值与索引举例:
@Entry
@Component
struct Index {
students:string[] = ["Alex", "Bob", "Charles", "David"]
build() {
Column() {
ForEach(this.students, (item:string, index:number) => {
Row() {
Text(index.toString())
.fontSize(50)
Blank()
Text(item)
.fontSize(50)
}
.width("80%")
})
}
.width('100%')
.height('100%')
}
}
使用 LazyForEach
语句
语法:
LazyForEach(
dataSource: IDataSource,
itemGenerator: (item: any, index: number) => void,
keyGenerator?: (item: any, index: number) => string
): void
用法与 ForEach
类似,其中数据源为 IDataSource
interface IDataSource {
totalCount(): number;
getData(index: number): Object;
registerDataChangeListener(listener: DataChangeListener): void;
unregisterDataChangeListener(listener: DataChangeListener): void;
}
totalCount
:获得数据总数getData
:获取索引值对应的数据registerDataChangeListener
:注册数据改变的监听器unregisterDataChangeListener
:注销数据改变的监听器状态:组件中的需要 @State
修饰器修饰的数据
特点:状态数据会通过声明式 UI 组件的方式展示到页面中,并且数据的变化会被 ArkUI 底层实时监控
如果 @State
装饰的变量是对象,则 ArkUI 会监视对象和其中属性值的变化
如果属性值是对象,且该对象的值发生了变化,则可以使用以下方法监视:
重新 new
一个对象
使用 @Observed
搭配 @ObjectLink
@Observed
class Car {
name: string
price: number
constructor(name: string, price: number) {
this.name = name
this.price = price
}
}
class Person {
name: string
car: Car
constructor(name: string, car: Car) {
this.name = name
this.car = car
}
}
@Component
struct CarInfo {
@ObjectLink car: Car
build() {
Text(`车名:${this.car.name}\n车价:${this.car.price}`)
}
}
@Entry
@Component
struct Index {
person: Person = new Person("张三", new Car("智界S7", 210000))
build() {
Column() {
Text(`姓名:${this.person.name}`)
CarInfo({ car: this.person.car })
Button("车价减 1000")
.onClick(() => {
this.person.car.price -= 1000
})
}
}
}
如果传递方法,需要绑定 this
举例:待办列表
@Observed
class TodoItem {}
@Component
struct TodoComponent {
@ObjectLink item: TodoItem
index: number
remove: (index: number) => void
customSize: number
build() {
Row() {
Button() {
Image($r("app.media.todo"))
.width(this.customSize)
}
Text(this.item.name)
Blank()
Button() {
Image($r('app.media.remove'))
.width(this.customSize)
}
.onClick(() => {
this.remove(this.index)
})
}
}
}
@Entry
@Component
struct Index {
@State TodoList: TodoItem[] = []
customSize: number = 25
newItemName: string = ""
remove(index: number) {
this.TodoList.splice(index, 1)
}
@Builder
Header() {}
build() {
Column({ space: 20 }) {
Text("待办列表")
this.Header()
List({ space: 16 }) {
ForEach(this.TodoList, (item: TodoItem, index: number) => {
ListItem() {
TodoComponent({
customSize: this.customSize,
item: item,
index: index,
remove: this.remove.bind(this)
})
}
})
}
}
}
}
@Prop
专门用于处理父子组件的之间单向的数据传递
举例:
@Component
struct Child {
@Prop message: string
build() {
Text(`Child: ${this.message}`)
.fontSize(20)
}
}
@Entry
@Component
struct Parent {
@State message: string = 'Hello World'
build() {
Column({ space: 30 }) {
Text(`Parent: ${this.message}`)
.fontSize(20)
.onClick(() => {
this.message = 'Changed'
})
Child({ message: this.message })
}
.width('100%')
.height('100%')
}
}
message
的值发生了变化,在 @Prop
的作用下,子组件也随着变化重新渲染区别于 @State
,@Prop
不需要在子组件初始化,而是等待来自父组件的数据
@Prop
只能装饰简单类型的属性
@Prop
的原理是:将父组件的属性值复制一份到子组件
@Link
与 @Prop
作用相同
@Link
可以双向数据传递,并且可以装饰任何类型的属性举例:
@Component
struct Child {
@Link message: string
build() {
Text(`Child: ${this.message}`)
.fontSize(20)
.onClick(() => {
this.message = 'Changed'
})
}
}
@Entry
@Component
struct Parent {
@State message: string = 'Hello World'
build() {
Column({ space: 30 }) {
Text(`Parent: ${this.message}`)
.fontSize(20)
Child({ message: $message })
}
.width('100%')
.height('100%')
}
}
message
的值发生了变化,在 @Link
的作用下,父组件也随着变化重新渲染如果在子组件使用 @Link
,则父组件传递时,需要使用 $
,如 子组件({ 子组件属性名: $父组件属性名 })
@Link
的原理是,将父组件属性的地址值传递给子组件
@Provide
与 @Consume
搭配使用,实现任意组件之间双向的数据传递
采用隐式数据传递
提供方可以为数据配置别名
举例:
@Component
struct Grandchild {
@Consume msg: string
build() {
Text(`Grandchild: ${this.msg}`)
.fontSize(20)
.onClick(() => {
this.msg = 'Change from grandchild'
})
}
}
@Component
struct Child {
build() {
Grandchild()
}
}
@Entry
@Component
struct Parent {
@Provide('msg') message: string = 'Hello World'
build() {
Column({ space: 30 }) {
Text(`Parent: ${this.message}`)
.fontSize(20)
.onClick(() => {
this.message = 'Change from parent'
})
Child()
}
.width('100%')
.height('100%')
}
}
此方法对性能有所损耗(缺点)
监视对象是组件中的数据,当数据发生改变,监视器就会触发相应的方法
举例:
@Entry
@Component
struct Index {
@State @Watch('calcTotal') array: number[] = [0, 1, 2, 3]
@State total: number = 0
calcTotal(): void {
this.total = 0
this.array.forEach(element => this.total += element);
}
aboutToAppear() {
this.calcTotal()
}
build() {
Column() {
Text(`数组全部元素和为:${this.total}`)
Button("向数组添加元素")
.onClick(() => {
this.array.push(10)
})
}
.width("100%")
.height('100%')
}
}
在 src/main/resources/base/profile/main_pages.json 中注册路由
{
"src": [
"pages/A",
"pages/B"
]
}
在页面中引入路由模块:import router from '@ohos.router'
在 A 页面调用方法:pushUrl(options: RouterOptions): Promise<void>
其中,RouterOptions
为:
interface RouterOptions {
url: string;
params?: Object;
}
import router from '@ohos.router'
@Entry
@Component
struct A {
build() {
Column() {
Text("A 页面")
.fontSize(50)
.fontWeight(FontWeight.Bold)
Button("跳转到 B 页面")
.onClick(() => {
router.pushUrl({ url: 'pages/B' })
})
}
.width("100%")
.height("100%")
}
}
replaceUrl(options: RouterOptions): Promise<void>
,区别在于 replaceUrl
方法会替换栈顶页面,导致无法使用下述 back
方法返回上一个页面在 B 页面调用方法:back(options?: RouterOptions ): void
import router from '@ohos.router'
@Entry
@Component
struct B {
build() {
Column() {
Text("B 页面")
.fontSize(50)
.fontWeight(FontWeight.Bold)
Button("返回")
.onClick(() => {
router.back()
})
}
.width('100%')
.height('100%')
}
}
使用 A 页面传递参数
router.pushUrl({
url: 'pages/B',
params: {
name: "张三",
age: 18
}
})
在 B 页面接受参数
interface IParams {
name: string
age: number
}
@Entry
@Component
struct B {
@State person: IParams = {
name: "",
age: 0
}
aboutToAppear() {
this.person = router.getParams() as IParams
}
build() {
Column() {
// ...
Text(`${this.person.name} - ${this.person.age}`)
}
}
}
路由模式有两种,包括:
路由模式在 pushUrl
方法的第二参数中指定,如:
router.pushUrl(
{ url: 'pages/B' },
router.RouterMode.Single
)
-End-