ArkTS之状态管理

5.状态管理

1.概述

1.基本概念

前文的描述中,我们构建的页面多为静态界面。如果希望构建一个动态的、有交互的界面,就需要引入“状态”的概念。

图1 效果图

上面的示例中,用户与应用程序的交互触发了文本状态变更,状态变更引起了UI渲染,UI从“Hello World”变更为“Hello ArkUI”。

在声明式UI编程框架中,UI是程序状态的运行结果,用户构建了一个UI模型,其中应用的运行时的状态是参数。当参数改变时,UI作为返回结果,也将进行对应的改变。这些运行时的状态变化所带来的UI的重新渲染,在ArkUI中统称为状态管理机制。

自定义组件拥有变量,变量必须被装饰器装饰才可以成为状态变量,状态变量的改变会引起UI的渲染刷新。如果不使用状态变量,UI只能在初始化时渲染,后续将不会再刷新。 下图展示了State和View(UI)之间的关系。

  • View(UI):UI渲染,指将build方法内的UI描述和@Builder装饰的方法内的UI描述映射到界面。
  • State:状态,指驱动UI更新的数据。用户通过触发组件的事件方法,改变状态数据。状态数据的改变,引起UI的重新渲染。

在阅读状态管理文档前,开发者需要对UI范式基本语法有基本的了解。建议提前阅读:基本语法概述声明式UI描述自定义组件-创建自定义组件

名词介绍

  • 状态变量:被状态装饰器装饰的变量,状态变量值的改变会引起UI的渲染更新。示例:@State num: number = 1,其中,@State是状态装饰器,num是状态变量。
  • 常规变量:没有被状态装饰器装饰的变量,通常应用于辅助计算。它的改变永远不会引起UI的刷新。以下示例中increaseBy变量为常规变量。
  • 数据源/同步源:状态变量的原始来源,可以同步给不同的状态数据。通常意义为父组件传给子组件的数据。以下示例中数据源为count: 1。
  • 命名参数机制:父组件通过指定参数传递给子组件的状态变量,为父子传递同步参数的主要手段。示例:CompA({ aProp: this.aProp })。
  • 从父组件初始化:父组件使用命名参数机制,将指定参数传递给子组件。子组件初始化的默认值在有父组件传值的情况下,会被覆盖。示例:
@Component
  struct MyComponent {
    @State count: number = 0;
    private increaseBy: number = 1;


    build() {
    }
  }


@Entry
  @Component
  struct Parent {
    build() {
      Column() {
        // 从父组件初始化,覆盖本地定义的默认值
        MyComponent({ count: 1, increaseBy: 2 })
      }
    }
  }
  • 初始化子组件:父组件中状态变量可以传递给子组件,初始化子组件对应的状态变量。示例同上。
  • 本地初始化:在变量声明的时候赋值,作为变量的默认值。示例:@State count: number = 0。

说明

当前状态管理的功能仅支持在UI主线程使用,不能在子线程、worker、taskpool中使用。

一句话数据驱动视图,视图通过组件的事件以及方法改变数据,从而引发页面的重新渲染。

2. 状态管理 V1 概述

装饰器总览

ArkUI状态管理V1提供了多种装饰器,通过使用这些装饰器,状态变量不仅可以观察在组件内的改变,还可以在不同组件层级间传递,比如父子组件、跨组件层级,也可以观察全局范围内的变化。根据状态变量的影响范围,将所有的装饰器可以大致分为

  • 管理组件内状态的装饰器:组件级别的状态管理,可以观察同一个组件树上(即同一个页面内)组件内或不同组件层级的变量变化。
  • 管理应用级状态的装饰器:应用级别的状态管理,可以观察不同页面,甚至不同UIAbility的状态变化,是应用内全局的状态管理。

从数据的传递形式和同步类型层面看,装饰器也可分为:

  • 只读的单向传递;
  • 可变更的双向传递。

图示如下,具体装饰器的介绍,可详见管理组件拥有的状态管理应用拥有的状态。开发者可以灵活地利用这些能力来实现数据和UI的联动。

上图中,Components部分的装饰器为组件级别的状态管理,Application部分为应用的状态管理。开发者可以通过@StorageLink/@LocalStorageLink实现应用和组件状态的双向同步,通过@StorageProp/@LocalStorageProp实现应用和组件状态的单向同步。

管理组件拥有的状态,即图中Components级别的状态管理:

  • @State:@State装饰的变量拥有其所属组件的状态,可以作为其子组件单向和双向同步的数据源。当其数值改变时,会引起相关组件的渲染刷新。
  • @Prop:@Prop装饰的变量可以和父组件建立单向同步关系,@Prop装饰的变量是可变的,但修改不会同步回父组件。
  • @Link:@Link装饰的变量可以和父组件建立双向同步关系,子组件中@Link装饰变量的修改会同步给父组件中建立双向数据绑定的数据源,父组件的更新也会同步给@Link装饰的变量。
  • @Provide/@Consume:@Provide/@Consume装饰的变量用于跨组件层级(多层组件)同步状态变量,可以不需要通过参数命名机制传递,通过alias(别名)或者属性名绑定。
  • @Observed:@Observed装饰class,需要观察多层嵌套场景的class需要被@Observed装饰。单独使用@Observed没有任何作用,需要和@ObjectLink、@Prop联用。
  • @ObjectLink:@ObjectLink装饰的变量接收@Observed装饰的class的实例,应用于观察多层嵌套场景,和父组件的数据源构建双向同步。

说明

@Observed/@ObjectLink可以观察嵌套场景,其他的状态变量仅能观察第一层,详情见各个装饰器章节的“观察变化和行为表现”小节。

管理应用拥有的状态,即图中Application级别的状态管理:

  • AppStorage是应用程序中的一个特殊的单例LocalStorage对象,是应用级的数据库,和进程绑定,通过@StorageProp@StorageLink装饰器可以和组件联动。
  • AppStorage是应用状态的“中枢”,将需要与组件(UI)交互的数据存入AppStorage,比如持久化数据PersistentStorage和环境变量Environment。UI再通过AppStorage提供的装饰器或者API接口,访问这些数据。
  • 框架还提供了LocalStorage,AppStorage是LocalStorage特殊的单例。LocalStorage是应用程序声明的应用状态的内存“数据库”,通常用于页面级的状态共享,通过@LocalStorageProp@LocalStorageLink装饰器可以和UI联动。

其他状态管理V1功能

@Watch用于监听状态变量的变化。

$$运算符:给内置组件提供TS变量的引用,使得TS变量和内置组件的内部状态保持同步。

2.管理组件拥有的状态(V1)

1.@State-组件内状态

@State 装饰器是管理组件内部状态的
@State装饰的变量,或称为状态变量
但是,并不是状态变量的所有更改都会引起UI的刷新,只有可以被框架观察到的修改才会引起UI刷新。

观察变化注意点:
●当装饰的数据类型为boolean、string、number类型时,可以观察到数值的变化。
●当装饰的数据类型为Object或数组时
○可以观察到自身的赋值的变化
○可以观察到对象属性赋值的变化,即Object.keys(observedObject)返回的所有属性
■注意:嵌套属性的赋值观察不到
○可以观察到数组本身的赋值和添加、删除、更新数组项的变化
■注意:数组项中属性的赋值观察不到


 

2.@Prop-父子单向同步

@Prop 装饰的变量可以和父组件建立单向的同步关系

@Prop 装饰的变量是可变的,但是变化不会同步回其父组件

注意:

  1. 修改父组件数据,会同步更新子组件
  2. 修改子组件@Prop 修饰的数据,子组件 UI 更新,更新后的数据不会同步给父组件
  3. 通过回调函数的方式修改父组件的数据,然后触发@Prop数据的更新

3.@Link-父子双向同步

使用@Link 可以实现父组件和子组件的双向同步:

@Link修饰的状态变量也能监听到浅层的数据变化

4.@Provide与@Consume-后代组件双向同步

将数据传递给后代,和后代的数据进行双向同步

// 写法 1:通过相同的变量名绑定
@Provide a: number = 0;
@Consume a: number;

// 写法 2通过相同的变量别名绑定
@Provide b: number = 0;
@Consume('b') c: number;
interface Person {
  name: string
  age: number
}

@Entry
@Component
  // 顶级组件
struct RootComponent {
  @Provide
  p: Person = {
    name: 'jack',
    age: 18
  }
  @Provide
  food: string = '西兰花炒蛋'

  build() {
    Column() {
      Text('顶级组件')
        .fontSize(30)
        .fontWeight(900)
      Text(JSON.stringify(this.p))
      Text(this.food)

      ParentComponent()
    }
    .padding(10)
    .height('100%')
    .backgroundColor('#ccc')
    .width('100%')
    .alignItems(HorizontalAlign.Center)
    .padding({ top: 100 })
  }
}


@Component
  // 二级组件
struct ParentComponent {
  // 编写 UI
  build() {
    Column({ space: 20 }) {
      Text('我是二级组件')
        .fontSize(22)
        .fontWeight(900)

      SonComponent()
    }
    .backgroundColor('#a6c398')
    .alignItems(HorizontalAlign.Center)
    .width('90%')
    .margin({ top: 50 })
    .padding(10)
    .borderRadius(10)

  }
}

@Component
  // 内层组件
struct SonComponent {
  // 相同变量名
  @Consume p: Person
  @Consume('food') f: string

  // 编写 UI
  build() {
    Column({ space: 20 }) {
      Text('我是内层组件')
        .fontSize(20)
        .fontWeight(900)
      Text(JSON.stringify(this.p))
      Text(this.f)
      Button('修改')
        .onClick(() => {
          this.p.name = 'rose'
          this.p.age = 99
          this.f += '!'
        })

    }
    .backgroundColor('#bf94e4')
    .alignItems(HorizontalAlign.Center)
    .width('90%')
    .margin({ top: 50 })
    .padding(10)
    .borderRadius(10)

  }
}
5.@Observed 与 ObjectLink

在线文档

问题:@State装饰器仅能观察到第一层的变化,对于多层嵌套的情况(比如对象数组等),他们的第二层属性变化是无法观察到的
解决:@Observed&@ObjectLink可以解决上述问题
@Observed&@ObjectLink作用:用于父子组件场景下,在涉及嵌套对象或数组中进行双向数据同步
●使用new创建被@Observed装饰的类,可以被观察到属性的变化
注意:ObjectLink修饰符不能用在Entry修饰的组件中
 

//【固定】1. @Observed 装饰类
@Observed
class ClassA{
  // 略
}

//2. 父组件
@Component 
struct ParentCom{
  // 【非固定写法】根据需求来定义数据
  @State 变量名: ClassA[] = [ new ClassA(),new ClassA(), ]
  @State 变量名:ClassA = new ClassA()  
  @State 变量名: ClassA[][] = [[new ClassA(),new ClassA()],[new ClassA(),new ClassA()] ]
  
}


// 【固定】3. 子组件
@Component 
struct ChildCom{
  @ObjectLink 变量名: ClassA
}

使用步骤:

  • interface 改为 类 class 并使用 @Observed 修饰
  • 通过 new 的方式完成数据的创建(通过 new 的方式来监测数据的改变)
  • 状态修饰符改为 @ObjectLink
    • 在父组件修改数据:不需要 splice
    • 在子组件修改数据
interface Person {
  id: number
  name: string
  age: number
}


@Entry
@Component
struct ObservedAndLink {
  @State personList: Person[] = [
    {
      id: 1,
      name: '张三',
      age: 18
    },
    {
      id: 2,
      name: '李四',
      age: 19
    },
    {
      id: 3,
      name: '王五',
      age: 20
    }
  ]

  build() {
    Column({ space: 20 }) {
      Text('父组件')
        .fontSize(30)
      List({ space: 10 }) {
        ForEach(this.personList, (item: Person, index: number) => {
          ItemCom({
            info: item,
            addAge: () => {
              item.age++
              this.personList.splice(index, 1, item)
            }
          })
        })
      }

    }
    .backgroundColor('#cbe69b')
    .width('100%')
    .height('100%')
    .padding(20)
  }
}

@Component
struct ItemCom {
  @Prop info: Person
  addAge = () => {

  }

  build() {
    ListItem() {
      Row({ space: 10 }) {
        Text('姓名:' + this.info.name)
        Text('年龄:' + this.info.age)
        Blank()
        Button('修改数据')
          .onClick(() => {
            this.addAge()
          })
      }
      .backgroundColor(Color.Pink)
      .padding(10)
      .width('100%')
    }
  }
}

@Observed
class Person {
  id: number
  name: string
  age: number

  constructor(id: number, name: string, age: number) {
    this.id = id
    this.name = name
    this.age = age
  }
}


@Entry
@Component
struct ObservedAndLink {
  @State personList: Person[] = [
    new Person(1, '张三', 18),
    new Person(2, '李四', 18),
    new Person(3, '王五', 18),
  ]

  build() {
    Column({ space: 20 }) {
      Text('父组件')
        .fontSize(30)
      List({ space: 10 }) {
        ForEach(this.personList, (item: Person, index: number) => {
          ItemCom({
            info: item,
            addAge: () => {
              item.age++
            }
          })
        })
      }

    }
    .backgroundColor('#cbe69b')
    .width('100%')
    .height('100%')
    .padding(20)
  }
}

@Component
struct ItemCom {
  @ObjectLink info: Person
  addAge = () => {

  }

  build() {
    ListItem() {
      Row({ space: 10 }) {
        Text('姓名:' + this.info.name)
        Text('年龄:' + this.info.age)
        Blank()
        Button('修改数据')
          .onClick(() => {
            this.addAge()
            // 这种写法也可以
            // this.info.age++
          })
      }
      .backgroundColor(Color.Pink)
      .padding(10)
      .width('100%')
    }
  }
}

3.管理应用拥有的状态(V1)

TIP

关于应用状态相关的内容需要使用模拟器或真机调试

到目前为止咱们学习的各种装饰器可以实现在一个组件树上共享状态。如果开发者要实现应用级的,或者多个页面的状态数据共享,就需要用到应用级别的状态管理的概念。ArkTS根据不同特性,提供了多种【应用状态管理】的能力:

  • LocalStorage:页面级UI状态共享(内存-非持久化状态,退出消失)
  • AppStorage:应用内状态-多 UIAbility 共享(内存-非持久化状态,退出消失)
  • PersistentStorage:全局持久化状态(磁盘-持久化状态,退出应用 数据同样存在)
  • Environment:应用程序运行的设备的环境参数(可读不可写)
    • 暗黑模式
    • 语言模式
    • 网络环境
1. LocalStorage

UIAbility内的状态管理

LocalStorage 是页面级的UI状态存储,通过 @Entry 装饰器接收的参数可以在页面内共享同一个 LocalStorage 实例。 LocalStorage 也可以在 UIAbility 内,页面间共享状态。

1.用法

import { router } from '@kit.ArkUI'

// class UserInfo {
//   name: string = ''
//   age: number = 0
// }
export interface UserInfo{
  name: string
  age: number
}

let userData: Record<string, UserInfo> = {
  'user': {
    name: 'jack',
    age: 18
  }
}
// ✨✨1. 实例化LocalStorage
export const storage = new LocalStorage(userData)

//✨✨ 2. 将LocalStorage实例设置给@Entry的参数
@Entry(storage)
@Component
struct Index {
  //✨✨ 3. 页面使用LocalStorage中的数据
  // 3.1 使用LocalStorageLink进行双向同步
  @LocalStorageLink('user')
  user: UserInfo = {
    name: 'rose',
    age: 18
  }
  // 3.2 使用LocalStorageProp进行单向同步
  // @LocalStorageProp('user')
  // user: UserInfo = {
  //   name: 'rose',
  //   age: 18
  // }

  build() {
    Column({ space: 15 }) {
      Text('我是首页:')
        .fontSize(40)
      // ✨✨✨4. UI使用LocalStorage的数据
      Text(JSON.stringify(this.user)).fontSize(20)

      Button('点击+1')
        .onClick(() => {
          this.user.age++
        })
      ChildA()
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

@Component
struct ChildA {
  @LocalStorageLink('user')
  user: UserInfo = {
    name: '',
    age: 0
  }

  build() {
    Column() {
      Text('我是子组件A')
        .fontSize(30)
      Button(this.user.name)
        .onClick(() => {
          this.user.name += '!'
        })
    }
    .backgroundColor(Color.Orange)
    .width('100%')

  }
}
2.AppStorage

模块页面数据共享

LocalStorage是针对UIAbility的状态共享- 一个UIAbility有多个页面,这些页面都可以通过 LocalStorage 共享数据

一个应用可能有若干个UIAbility,如果要在多个 UIAbility 共享数据,就可以使用 AppStorage

class User {
  name: string = ''
  age: number = 0
}

// ✨✨1. 给AppStorage设置初始数据
AppStorage.setOrCreate<User>('user', { name: 'jack', age: 18 })

@Entry
@Component
struct AppStorageUse01 {
  //✨✨ 2. 组件内获取AppStorage的数据
  @StorageLink('user')
  user: User = {
    name: '',
    age: 0
  }

  build() {
    Column({ space: 15 }) {
      Text(JSON.stringify(this.user))
        .fontSize(20)
      //✨✨ 3. 使用AppStorage数据
      Button('点击修改名字')
        .fontSize(30)
        .onClick(() => {
          this.user.name += '!'
        })
     Button('点击修改年龄')
        .fontSize(30)
        .onClick(() => {
          this.user.age++
        })


      Divider()
      ChildA()
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

@Component
struct ChildA {
  @StorageProp('user')
  user: User = {
    name: '',
    age: 0
  }

  build() {
    Column({ space: 15 }) {
      Text('子组件 A:')
        .fontColor(Color.White)
      Text(JSON.stringify(this.user))
     Button('点击修改名字')
        .fontColor(Color.White)
        .onClick(() => {
          this.user.name += '!'
        })

      Button('点击修改年龄')
        .fontColor(Color.White)
        .onClick(() => {
          this.user.age++
        })
    }
    .width('100%')
    .padding(10)
    .backgroundColor(Color.Orange)
  }
}

如用不需要持久化我们可以直接省略第一步

@StorageLink('isShow')

isShow: boolean = true

3.PersistentStorage

状态持久化

模拟器或者真机中查看效果-> 查看路径如下

LocalStorage和AppStorage都是运行时的内存,在应用退出后就没有了,如果要在应用退出后再次启动AppStorage依然能保存选定的结果,这就需要用到PersistentStorage。

用法:

PersistentStorage.PersistProp('属性名', 值)

后续直接通过 AppStorage 的 Api 来获取并修改即可,AppStorage 的修改会自动同步到PersistentStorage中

保存简单类型

number, string, boolean, enum 等简单类型都支持

核心步骤:

  1. 初始化PersistentStorage
  2. 通过 AppStorage 获取并修改数据
  3. 重启应用,检测结果
PersistentStorage.persistProp<string>('info','感觉自己闷闷哒')

@Entry
@Component
struct PersistentStoragePage01 {
  @StorageLink('info')
  info:string=''

  build() {
    Row() {
      Column() {
        Text(this.info)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
          .onClick(()=>{
            this.info+='!'
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}

保存复杂类型

接下来看看复杂类型

支持的复杂类型:

  • 可以被JSON.stringify()和JSON.parse()重构的对象。例如Date, Map, Set等内置类型则不支持,以及对象的属性方法不支持持久化。

划重点:自己定义的 class、interface 基本都是支持的

不允许的类型和值有:

  • 不支持嵌套对象(对象数组,对象的属性是对象等)。因为目前框架无法检测AppStorage中嵌套对象(包括数组)值的变化,所以无法写回到PersistentStorage中。
  • 不支持 undefined 和 null
interface FoodInfo{
  name:string
  price:number
}
PersistentStorage.persistProp('foods',[
  {name:'西兰花炒蛋',price:10},
  {name:'猪脚饭',price:15},
  {name:'剁椒鱼头',price:14},
])
1
@Entry
@Component
struct PersistentStoragePage02 {
  @StorageLink('foods')
  foods:FoodInfo[]=[]

  build() {
    Row() {
      Column() {
        Text(JSON.stringify(this.foods))
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
        Button('点击添加新的菜')
          .onClick(() => {
            this.foods.push({
              name:'红烧肉',
              price:20
            })
          })

      }
      .width('100%')
    }
    .height('100%')
  }
}

说在最后:

  • 持久化变量最好是小于2kb的数据,如果开发者需要存储大量的数据,建议使用数据库api
4.Environment

设备环境查询

开发者如果需要应用程序运行的设备的环境参数,以此来作出不同的场景判断,比如多语言,暗黑模式等,需要用到Environment设备环境查询。

使用步骤:

  1. Environment.envProp('languageCode', 默认值); // 将设备信息存入 AppStorage 中,如果读取不到使用默认值
  2. 通过 AppStorage 获取 并使用即可

注:只能读取,无法修改

数据类型

描述

accessibilityEnabled

boolean

获取无障碍屏幕读取是否启用。

colorMode

ColorMode

色彩模型类型:选项为ColorMode.LIGHT: 浅色,ColorMode.DARK: 深色。

fontScale

number

字体大小比例,范围: [0.85, 1.45]。

fontWeightScale

number

字体粗细程度,范围: [0.6, 1.6]。

layoutDirection

LayoutDirection

布局方向类型:包括LayoutDirection.LTR: 从左到右,LayoutDirection.RTL: 从右到左。

languageCode

string

当前系统语言值,取值必须为小写字母, 例如zh。

Environment.envProp("accessibilityEnabled", 'aaaaaaaa')
Environment.envProp("fontScale", 'bbbb')
Environment.envProp("languageCode", "cccc")
Environment.envProp("colorMode", "ddddd")
@Entry
@Component
struct Index {
  @State message: string = 'Hello World';

  aboutToAppear(): void {
    console.log('测试','获取无障碍屏幕读取是否启用', AppStorage.get("accessibilityEnabled"))
    console.log("测试",'字体大小比例', AppStorage.get("fontScale"))
    console.log('测试','当前系统语言值', AppStorage.get("languageCode"))
    console.log('测试','色彩模型类型', AppStorage.get("colorMode"))

  }

  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
      }
      .width('100%')
    }
    .height('100%')
  }
}

4.其他状态管理

1.@Watch装饰器:状态变量更改通知

如果开发者需要关注某个状态变量的值改变后,触发一段逻辑的执行,可以使用 @Watch 为状态变量设置回调函数。

注意:

Watch无法单独使用,必须配合状态装饰器,比如@State、@Prop、@Link

@State、@Prop、@Link 等装饰器在 @Watch 装饰之前

@State / @Prop / @Link 其中之一
@Watch('方法名')
info:string=''

方法名(){
  // 数据改变之后会触发
}
/*
 * 1. 定义一个状态变量
 * 2. 在这个状态变量上使用@Watch来修饰
 * 3. 定义一个函数来配合@Watch的使用,至于这个函数的方法体写什么逻辑不固定
 * */

@Entry
@Component
struct Index {

  @State
  @Watch('loadData')
  count:number = 100

  @State
  @Watch('loadData')
  msg:string = 'hello'


  // source参数表示是哪个状态变量触发的这个函数
  // 进来可以用在判断不同的状态变量引起的回调,就处理不同的逻辑
  loadData(source:string){
    AlertDialog.show({message:this.count.toString() + source})
  }

  build() {
    Column() {

      Button('count='+this.count)
        .onClick(()=>{
          // this.count++
          this.msg = 'hi'
        })

    }
    .height('100%')
    .width('100%')
    .backgroundColor(Color.Pink)

  }
}
2.$$语法:内置组件双向同步

$$运算符为系统内置组件提供TS变量的引用,使得TS变量和系统内置组件的内部状态保持同步。

内部状态具体指什么取决于组件。例如,TextInput组件的text参数。

说明

$$还用于@Builder装饰器的按引用传递参数,开发者需要注意两种用法的区别。

使用规则

  • 当前$$支持基础类型变量,以及@State@Link@Prop装饰的变量。
  • 当前$$支持的组件:

组件

支持的参数/属性

起始API版本

Checkbox

select

10

CheckboxGroup

selectAll

10

DatePicker

selected

10

TimePicker

selected

10

MenuItem

selected

10

Panel

mode

10

Radio

checked

10

Rating

rating

10

Search

value

10

SideBarContainer

showSideBar

10

Slider

value

10

Stepper

index

10

Swiper

index

10

Tabs

index

10

TextArea

text

10

TextInput

text

10

TextPicker

selected、value

10

Toggle

isOn

10

AlphabetIndexer

selected

10

Select

selected、value

10

BindSheet

isShow

10

BindContentCover

isShow

10

Refresh

refreshing

8

GridItem

selected

10

ListItem

selected

10

  • $$绑定的变量变化时,会触发UI的同步刷新。

使用示例

TextInput方法的text参数为例:

// xxx.ets
@Entry
  @Component
  struct TextInputExample {
    @State text: string = ''
    controller: TextInputController = new TextInputController()


    build() {
      Column({ space: 20 }) {
        Text(this.text)
        TextInput({ text: $$this.text, placeholder: 'input your word...', controller: this.controller })
          .placeholderColor(Color.Grey)
          .placeholderFont({ size: 14, weight: 400 })
          .caretColor(Color.Blue)
          .width(300)
      }.width('100%').height('100%').justifyContent(FlexAlign.Center)
    }
  }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值