HarmonyOS组件基础 原创

liuyang8888
发布于 2025-3-17 12:22
765浏览
0收藏

1.组件-什么是ArkTS

ArkTS是HarmonyOS优选的主力应用开发语言。ArkTS围绕应用开发在TypeScript(简称TS)生态基础上做了进一步扩展,继承了TS的所有特性,是TS的超集。

说明: 也就是前端开发过程中所有的js/ts语法大部分支持的,比如es6中的箭头函数-模板字符串-promise-async/await-数组对象方法。

注意: 根据Next版本的内部沟通,下一版本的ArkTs对类型最了更一步的限制。

https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/typescript-to-arkts-migration-V5

 

HarmonyOS组件基础-鸿蒙开发者社区

这里注意:ArtTS绝不是TS。

①TS在前端中虽然有类型约束,但是他会编译成js去运行。

②ArtTS编译后直接映射字节码-编译过程带类型。

扩展能力如下:

①基本语法

  • 定义声明式UI、自定义组件、动态扩展UI元素;
  • 提供ArkUI系统组件,提供组件事件、方法、属性;
  • 共同构成 UI 开发主体。

②状态管理

  • 组件状态、组件数据共享、应用数据共享、设备共享;

③渲染控制

  • 条件渲染、循环渲染、数据懒加载;

声明式UI

·       ​https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-declarative-ui-description-V5​

HarmonyOS组件基础-鸿蒙开发者社区

总结:

①AktTS提供原有前端范畴内的一切TypeScript和JavaScript的类型及方法支持。

②不是所有都支持- 比如解构不支持(Next版本)。

③ArkTS采用声明式UI的方法来绘制页面,设置属性,绑定事件。

2.组件结构

接下来,我们来解析我们的UI的结构。

ArkTS通过装饰器 @Component 和 @Entry 装饰 struct 关键字声明的数据结构,构成一个自定义组件。

自定义组件中提供了一个 build 函数,开发者需在该函数内以链式调用的方式进行基本的 UI 描述,UI 描述的方法请参考 UI 描述规范。

(1)struct-自定义组件基于struct

实现

要想实现一段UI的描述,必须使用struct关键字来声明- 注意不能有继承关系-组件名不能系统组件名重名。

语法: struct 组件名 {}。

@Component
struct Index {

}
@CustomDialog 
struct Index2 {

}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.


struct关键字声明的UI描述-必须被@Component或者@CustomDialog修饰。

(2)Component修饰符

Component装饰器只能修饰struct关键字声明的结构,被修饰后的struct具备组件的描述(渲染)能力。

(3)build函数

用于定义组件的UI描述,一个struct结构必须实现build函数。

@Component
struct MyComponent {
  build() {
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

build函数是组件(Component)必须提供以及实现的一个函数,build函数可以没有内容,如果有的话,必须有且只有一个​​容器组件​​(可以放置子组件的组件)- 只有entry里面有限制- component里面没有限制。

常见容器组件- Flex-Column-Row-List-Grid-Panel。

(4)entry修饰符

entry将自定义组件定义为UI页面的入口,也就是我们原来前端常说的一个页面,最多可以使用entry装饰一个自定义组件(在一个ets文件中)-如下面的代码就是不被允许的。

// 错误示例
@Entry
@Component
struct Index {
  build() {

  }
}
@Entry
@Component
struct Index2 {
  build() {

  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.


entry修饰的组件,最终会被注册,具体文件位置-main/resources/base/profile/main_pages.json。

①自动注册-新建组件时,采用新建Page的方式。

②手动注册-新建一个ets文件,自己在main_pages.json中手动添加路径。

注意:

如果手动删除了某一个带entry的组件,你需要手动去main_page中去删除该路径,否则编译会报错。

(5)组件复用

在很多情况下,由于业务的复杂度,经常会将一个大的业务拆成若干个组件,进行组装,这里我们非常灵活的复用组件,比如:

HarmonyOS组件基础-鸿蒙开发者社区

可以把上图抽象成三个组件- Header- Main- Footer。

@Entry
@Component
struct Index {
  @State message: string = 'Hello
World'

  build() {
    //
它的子组件都会以纵向方式排列
    Column()
{
      Header()
      Main()
      Footer()
    }
  }
}

@Component
struct Header {
  build() {
    Row(){
      Text("Header")
    }
      .width('100%')
      .height(50)
      .backgroundColor(Color.Pink)
    .justifyContent(FlexAlign.Center)
  }
}

@Component
struct Main {
  build() {
    Row(){
      Text("Main")
        .fontColor(Color.White)
    }
    .width('100%')
    .height(200)
    .backgroundColor(Color.Blue)
    .justifyContent(FlexAlign.Center)
  }
}

@Component
struct Footer {
  build() {
    Row(){
      Text("Footer")
        .fontColor(Color.White)
    }
    .width('100%')
    .height(50)
    .backgroundColor(Color.Pink)
    .justifyContent(FlexAlign.Center)
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.


运行效果,如图所示:

HarmonyOS组件基础-鸿蒙开发者社区

总结:

· 一个UI描述必须使用struct来声明,不能继承。

· struct必须被Component或者CustomDialog修饰。

· struct必须实现build方法,build方法可以没有元素,但是有的话有且只有一个可容纳子组件的容器组件(entry修饰的组件)。

· entry修饰符表示该组件是页面级组件,一个文件中只允许修饰一个struct组件。

· 采用分拆组件的形式可以有效解解耦我们的业务。

3.系统组件(ArkUI)

常用系统组件:

Button Text Column Row Flex Stack Scroll List TextInput Image ​更多组件​。

组件使用:

· Text 文本组件-(Span子组件)

· Column 列组件,纵向排列,Flex布局主轴是Y (任意子组件)

· Row 行组件,横向向排列,Flex布局主轴是X (任意子组件)

· Flex 以弹性方式布局子组件的容器组件。(

存在二次布局,官方推荐有性能要求,使用Column和Row代替) (任意子组件)

· Button 按钮组件 (单子组件)

· TextInput 输入框组件 (无子组件)

· Image (无子组件)

· Button (单个子组件)

· List (限制ListItem子组件)

· Scroll (限制单个子组件)

组件使用语法:

· 使用组件采用组件名() 的语法

· 有构造参数采用组件名(参数)的语法

· 组件里放置子组件采用组件名() {子组件的语法 } 的链式语法

· 组件设置属性采用组件名().width().height() 的语法

· 组件又有属性又有子组件采用组件名(){ ...子组件 }.width().height() 的语法

接下来,我们来实现一个布局的小例子测试一下我们的能力。

(1)横向布局

实现效果:

HarmonyOS组件基础-鸿蒙开发者社区

代码实现:

@Entry
@Component
struct Index {
  @State message: string = 'Hello
World'
  build() {
    Row(){
      Column(){
        Row({
space:15 }) {
          Column()
            .width(100)
            .height(200)
            .backgroundColor(Color.Pink)
          Column()
            .width(100)
            .height(200)
            .backgroundColor(Color.Red)
          Column()
            .width(100)
            .height(200)
            .backgroundColor(Color.Blue)
        }
        .width('100%')
        .justifyContent(FlexAlign.Center)
      }
      .width('100%')
    }
    .height('100%')
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.

(2)纵向布局

实现效果:

HarmonyOS组件基础-鸿蒙开发者社区

代码实现:

@Entry
@Component
struct Index {
  build() {
    Column(){
      RowCase()
      ColumnCase()
    }.height('100%').backgroundColor(Color.Grey)
  }
}
@Component
struct RowCase {
  build() {
    Row(){
      Column().height(150).width(100).backgroundColor(Color.Pink)
      Column().height(150).width(100).backgroundColor(Color.Red)
      Column().height(150).width(100).backgroundColor(Color.Blue)
    }
    .width('100%')
    .alignItems(VerticalAlign.Top)
    .justifyContent(FlexAlign.SpaceAround)
  }
}

@Component
struct ColumnCase {
  build() {
    Column(){
      Column().height(100).width(150).backgroundColor(Color.Pink)
      Column().height(100).width(150).backgroundColor(Color.Red)
      Column().height(100).width(150).backgroundColor(Color.Blue)
    }.height(400).width('100%').justifyContent(FlexAlign.SpaceEvenly)
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.


(3)Flex横纵向

实现效果:

HarmonyOS组件基础-鸿蒙开发者社区

代码实现:

@Entry
@Component
struct Index {
  @State message: string = 'Hello
World'
  build() {
    Scroll(){
      Row(){
        Column(){
          Flex({
direction: FlexDirection.Row,
justifyContent: FlexAlign.SpaceAround }) {
            Column()
              .width(100)
              .height(200)
              .backgroundColor(Color.Pink)
            Column()
              .width(100)
              .height(200)
              .backgroundColor(Color.Red)
            Column()
              .width(100)
              .height(200)
              .backgroundColor(Color.Blue)
          }
          .margin({
            top: 200
          })
        }
        .width('100%')
      }
    }
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.

在arkUI中,我们的内容如果超过了屏幕显示,则不会显示滚动条,需要使用Scroll来包裹。

需要注意的是:

该组件滚动的前提是主轴方向大小小于内容大小。子组件不要设置高度,否则不能滚动。

4.组件事件

监听原生组件的事件和设置属性的方式是一样的都是链式调用,值得注意的是,我们注册事件都要使用箭头函数的写法,HarmonyOS 5.0版本会有对于匿名函数function的限制。

尝试给一个TextInput和一个按钮注册一个值改变事件和点击事件。

(1)事件定义

实现效果:

HarmonyOS组件基础-鸿蒙开发者社区

点击登录后的效果:

HarmonyOS组件基础-鸿蒙开发者社区

代码实现:

@Entry
@Component
struct Index {
  build() {
    Column({
space: 10 }) {
      TextInput({
placeholder: '请输入用户名' })
        .onChange((value) => {
          AlertDialog.show({
message: value })
        })
      Button('登录').width('100%').onClick((event: ClickEvent) => {
        AlertDialog.show({
message: '点击登录' })
      })
    }
    .width('100%')
    .height('100%')
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.

请注意:在注册事件中的逻辑务必使用箭头函数() => {}极不推荐function() {}

①因为function中this指向为undefind

②HarmonyOS 5.0不再支持funtion匿名函数声明

③箭头函数中的this指向当前struct实例,可以方便的调用方法和获取属性

当我们事件处理逻辑比较复杂,写在UI描述中无法抽提的时候,我们可以在struct结构体中定义。

(2)属性定义

当我们需要在组件中记录一些状态时,变量应该显示的在struct中声明,并注明类型,比如-登录账户和密码。

struct Event {
  loginName: string = ""
  password: string = ""
}
  • 1.
  • 2.
  • 3.
  • 4.

我们看代码示例时,会发现 public和private关键字,

如果不写或者写public 表示该属性可被外界即父组件赋值,

如果写private表示该属性只会被该组件的this获取。

下面实现一个简单的登录过程:

示例代码:

@Entry
@Component
struct Index {
  username: string = ''
  pwd: string = ''

  login(){
    AlertDialog.show({
			message: `username:${this.username}-pwd: ${this.pwd}` })
  }

  build() {
    Column({space: 10 }) {
      TextInput({placeholder: '请输入用户名' })
        .onChange((value) => {
          this.username = value
          console.log('i-log', value)
        })

      TextInput({placeholder: '请输入密码' })
        .type(InputType.Password)
        .onChange((value) => {
          this.pwd= value
          console.log('i-log', value)
        })

      Button('登录').width('100%').onClick((event: ClickEvent) => {
       this.login()
      })
    }
    .width('100%')
    .height('100%')
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.

说明

promptAction和AlertDailog都可以弹出提示 promptAction需要引入包,AlertDialog不需要引入就可以直接使用。

再加一个小需求,当用户名和密码为空时,不让用户点按钮。

代码如下:

@Entry
@Component
struct Index {

  username: string = ''
  pwd: string = ''

  login(){
    AlertDialog.show({message: `username:${this.username}-pwd: ${this.pwd}` })
  }

  isSubmitFn(): boolean{
    return this.username!= '' && this.pwd!= ''
  }

  build() {
    Column({space: 10 }) {
      TextInput({placeholder: '请输入用户名' })
        .onChange((value) => {
          this.username = value
          console.log('i-log', value)
        })

      TextInput({placeholder: '请输入密码' })
        .type(InputType.Password)
        .onChange((value) => {
          this.pwd = value
          console.log('i-log', value)
        })

      Button('登录')
        .enabled(this.isSubmitFn())
        .width('100%').onClick((event: ClickEvent) => {
       this.login()
      })
    }
    .width('100%')
    .height('100%')
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.


我们发现,好像没有变化!!!为什么? 因为我们定义的变量是非响应式数据,值的变化无法导致build函数重新执行, 这就需要引出State修饰符了。

响应式数据- 数据驱动视图更新。

5.组件状态

@State装饰的变量,或称为状态变量,一旦变量拥有了状态属性,就和自定义组件的渲染绑定起来。当状态改变时,UI会发生对应的渲染改变。

如何使用 @State 定义一个状态变量?

(1)组件变量,不具备驱动UI更新能力。

  @State
  username: string = ''

  @State
  pwd: string = ''
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

加上该修饰符后,你惊奇的发现按钮随着数据的变化在变化,因为我们在值改变的时候赋值,造成了build的重新执行,isSubmitFn 函数会重新执行,来保证我们状态的变化。

需要注意的是,State修饰的类型包括:

Object、class、string、number、boolean、enum类型,以及这些类型的数组。类型必须被指定。不支持any,不支持简单类型和复杂类型的联合类型,不允许使用undefined和null。

接下来,我们完成一个数据修改的案例,来看下state的特性。

HarmonyOS组件基础-鸿蒙开发者社区

步骤1:先声明一个User类,interface是ArkTS主推的定义对象类型的形式。

interface Address{
  province: string
  city: string
  area: string
}

interface  User {
  name: string
  age: number
  address: Address
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

完整代码如下:

interface Address{
  province: string
  city: string
  area: string
}

interface  User {
  name: string
  age: number
  address: Address
}

@Entry
@Component
struct StateCase {
  @State user: Partial<User>  = {
    name: '张三',
    age: 20,
    address: {
      province: '广东省',
      city: '深圳市',
      area: '南山区'
    }
  }

  build() {
    Row()
{
      Column()
{
        Text(JSON.stringify(this.user))
        Row({
space: 15 }) {
          Text("姓名:")
          TextInput({
text: this.user.name
}).layoutWeight(1)
        }.padding(10)
        Row({
space: 15 }) {
          Text("年龄:")
          TextInput({
text: this.user.age?.toString()
}).layoutWeight(1)
        }.padding(10)
        Row({
space: 15 }) {
          Text("地址:")
          TextInput({
text: this.user.address?.province
}).layoutWeight(1)
          TextInput({
text: this.user.address?.city
}).layoutWeight(1)
          TextInput({
text: this.user.address?.area
}).layoutWeight(1)
        }.padding(10)
      }
      .width('100%')
    }
    .height('100%')
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.


点击修改数据按钮,设置新数据

运行效果:

HarmonyOS组件基础-鸿蒙开发者社区

        点击修改数据,可以修改用户名

HarmonyOS组件基础-鸿蒙开发者社区

代码如下:
    
interface IAddress{
  province: string
  city: string
  area: string
}

interface IUserInfo{
  username: string
  age: number
  address: IAddress
}


export class IAddressModel implements IAddress {
  province: string = ''
  city: string = ''
  area: string = ''

  constructor(model: IAddress) {
    this.province= model.province
    this.city= model.city
    this.area= model.area
  }
}
export class IUserInfoModel implements IUserInfo {
  username: string = ''
  age: number = 0
  address: IAddress = new IAddressModel({} as IAddress)

  constructor(model: IUserInfo) {
    this.username= model.username
    this.age= model.age
    this.address= model.address
  }
}


@Entry
@Component
struct StateCase2 {

  @State
  userInfo: IUserInfoModel = new IUserInfoModel({
    username: '李四',
    age: 21,
    address: new IAddressModel({
      province: '广东',
      city: '广州',
      area: '黄埔'
    })
  })

  build() {
    Column({space: 10}) {
      Row(){
        Text('用户名:')
          .width(80)
        Text(this.userInfo.username).layoutWeight(1)
          .borderRadius(40)
          .backgroundColor('#ccc')
          .height(40)
          .padding({left: 10,right: 10 })
      }
      .width('100%')
      .justifyContent(FlexAlign.SpaceBetween)

      Row(){
        Text('年龄:')
          .width(80)
        Text(this.userInfo.age.toString()).layoutWeight(1)
          .borderRadius(40)
          .backgroundColor('#ccc')
          .height(40)
          .padding({left: 10,right: 10 })
      }
      .width('100%')
      .justifyContent(FlexAlign.SpaceBetween)
      Row(){
        Text('地址:')
          .width(80)
        Text(this.userInfo.address.province)
          .borderRadius(40)
          .backgroundColor('#ccc')
          .height(40)
          .padding({left: 10,right: 10 })
        Text(this.userInfo.address.city)
          .borderRadius(40)
          .backgroundColor('#ccc')
          .height(40)
          .padding({left: 10, right: 10})
        Text(this.userInfo.address.area)
          .borderRadius(40)
          .backgroundColor('#ccc')
          .height(40)
          .padding({left: 10,right: 10 })
      }
      .width('100%')
      .justifyContent(FlexAlign.SpaceBetween)

      Button('修改数据').width('100%').onClick((event: ClickEvent) => {
        this.userInfo.username= Math.random().toFixed(2)
      })
    }
    .padding(20)
    .width('100%')
    .height('100%')
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.

大家发现,如果state是一个对象,我们改第一层的数据没问题,但是第二层的数据不触发更新,怎么办?

我们依然可以改第一层的数据。如:

this.userInfo.address.area = '天河'
  • 1.

代码如下:

interface IAddress{
  province: string
  city: string
  area: string
}
 
interface IUserInfo{
  username: string
  age: number
  address: IAddress
}
 
 
export class IAddressModel implements IAddress {
  province: string = ''
  city: string = ''
  area: string = ''
 
  constructor(model: IAddress) {
    this.province = model.province
    this.city = model.city
    this.area = model.area
  }
}
export class IUserInfoModel implements IUserInfo {
  username: string = ''
  age: number = 0
  address: IAddress = new IAddressModel({} as IAddress)
 
  constructor(model: IUserInfo) {
    this.username = model.username
    this.age = model.age
    this.address = model.address
  }
}
 
 
@Entry
@Component
struct StateCase3 {
 
  @State
  userInfo: IUserInfoModel = new IUserInfoModel({
    username: 'mark',
    age: 21,
    address: new IAddressModel({
      province: '广东',
      city: '广州',
      area: '黄埔'
    })
  })
 
  build() {
    Column({space: 10}) {
      Row() {
        Text('用户名:')
          .width(80)
        Text(this.userInfo.username).layoutWeight(1)
          .borderRadius(40)
          .backgroundColor('#ccc')
          .height(40)
          .padding({ left: 10, right: 10 })
      }
      .width('100%')
      .justifyContent(FlexAlign.SpaceBetween)
 
      Row() {
        Text('年龄:')
          .width(80)
        Text(this.userInfo.age.toString()).layoutWeight(1)
          .borderRadius(40)
          .backgroundColor('#ccc')
          .height(40)
          .padding({ left: 10, right: 10 })
      }
      .width('100%')
      .justifyContent(FlexAlign.SpaceBetween)
 
 
      Row() {
        Text('地址:')
          .width(80)
        Text(this.userInfo.address.province)
          .borderRadius(40)
          .backgroundColor('#ccc')
          .height(40)
          .padding({ left: 10, right: 10 })
        Text(this.userInfo.address.city)
          .borderRadius(40)
          .backgroundColor('#ccc')
          .height(40)
          .padding({ left: 10, right: 10 })
        Text(this.userInfo.address.area)
          .borderRadius(40)
          .backgroundColor('#ccc')
          .height(40)
          .padding({ left: 10, right: 10 })
      }
      .width('100%')
      .justifyContent(FlexAlign.SpaceBetween)
 
      Button('修改数据').width('100%').onClick((event: ClickEvent) => {
        this.userInfo.username = Math.random().toFixed(2)
        this.userInfo.address.area = '天河'
      })
    }
    .padding(20)
    .width('100%')
    .height('100%')
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
收藏
回复
举报


回复
    相关推荐
    恭喜您,今日已阅读两篇内容,特奖励+2声望, 快来领取吧。