装饰器,状态管理和if判断(HarmonyOS学习第六课)

@Builder装饰器-自定义构建函数

前面介绍了如何创建一个自定义组件。该自定义组件内部UI结构固定,仅与使方法进行数据传递。ArkUI还提供了一种更轻量的UI 元素复用机制@Builder,@Builder

所装饰的函数遵循build( )函数语法规则,开发者可以将重复使用的UI 元素抽象成一个方法,在 build 方法里调用。 为了简化语言,我们将@Builder 装饰的函数也称为“自定义构建函数”。从API version 9开始,该装饰器支持在ArkTS卡片中使用。

装饰器使用说明:

语法的定义

@Builder MyBuilderFunction( ){...}

使用方法

this.MyBuilderFunction(){...}

  • 允许在自定义组件内定义一个或多个@Builder 方法,该方法被认为是该组件的私有、特殊类型的成员函数。

  • 自定义构建函数可以在所属组件的build 方法和其他自定义构建函数中调用,但不允许在组件外调用。

  • 在自定义函数体中,this指代当前所属组件,组件的状态变量可以在自定义构建函数内访问。建议通过this访问自定义组件的状态变量而不是参数传递

全局自定义构建函数

语法的定义

@BUilder function MyGlobalBuilderFunction(){...}

使用方法

MyGlobalBuilderFunction()
  • 全局的自定义构建函数可以被整个应用获取,不允许使用this和bind方法。

  • 如果不涉及组件状态变化,建议使用全局的自定义构建方法

参数传递规则

自定义构建函数的参数传递有按值传递和按引用传递两种,均需遵守以下规则:

参数的类型必须与参数声明的类型一致,不允许undefined、nu1l和返回undefined、null的表达式

引用传参(最常用)

//自定义一个构建函数
//引用传参使用$$符号
@Builder
function  MyBulilder($$:{username:string}){
​
//用的时候也要使用$$
  Column(){
    Text(`hello ${$$.username}`)
      .fontSize(40)
      .margin(20)
  }
}
​
@Entry
@Component
​
struct  Parent{
​
  @State person_name: string='张三'
​
  build(){
    Column(){
      Divider()
      MyBulilder({username: this.person_name})
      Button('改变值').onClick(()=>{
        this.person_name ='李四'
      })
    }
  }
}

值传参(了解 并不实用)

//自定义一个构建函数
//按值传参
@Builder
function  MyBulilder(username:string){
​
​
  Column(){
    Text(`hello ${username}`)
      .fontSize(40)
      .margin(20)
  }
}
​
@Entry
@Component
​
struct  Parent{
​
  @State person_name: string='张三'
​
  build(){
    Column(){
      Divider()
      MyBulilder(this.person_name)
      Button('改变值').onClick(()=>{
        this.person_name ='李四'
      })
    }
  }
}

状态管理

状态管理概述

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

在本章节开始的案例中,用户与应用程序的交互触发了文本状态变更,状态变更引起了UI 渲染,UI 从“Hello world”变更为“Hello rkUI”,这个过程就用到了状态。

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

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

  • View(UI):UI 渲染,指将build 方法内的 UI 描述和@Builder 装饰的方法内的UI 描述映射到界面。

  • state:状态,指驱动U更新的数据。用户通过触发组件的事件方法,改变状态数据。状态数据的改变,引起UI的重新渲染。

基本概念

  • 状态变量:被状态装饰器装饰的变量,状态变量值的改变会引起UI的染更新。示例:@State num: number=1,其中,@State是状态装饰器,num是状态变量。

  • 常规变量:没有被状态装饰器装饰的变量,通常应用于辅助计算。它的改变永远不会引起UI的刷新。以下示例中increaseBy 变量为常规变量。

  • 数据源/同步源:状态变量的原始来源,可以同步给不同的状态数据。通常意义为父组件传给子组件的数据。以下示例中数据源为count:1。

  • 命名参数机制:父组件通过指定参数传递给子组件的状态变量,为父子传递同步参数的主要手段。示例:CompA:({aPrp:this.aProp})。

  • 从父组件初始化:父组件使用命名参数机制,将指定参数传递给子组件。子组件初始化的默认值在有父组件传值的情况下,会被覆盖。

  • 初始化子节点:父组件中状态变量可以传递给子组件,初始化子组件对应的状态变量。

  • 本地初始化:在变量声明的时候赋值,作为变量的默认值。示例:@statecount:number =0

管理组件拥有的状态

@State装饰器-组件内状态

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

在状态变量相关装饰器中,@state是最基础的,使变量拥有状态属性的装饰器,它也是大部分状态变量的数据源。从Pversion9开始,该装饰器支持在ArkTs 卡片中使用。

概述

@State装饰的变量,与声明式范式中的其他被装价变量一样,是私有的,只能从组件内部访问,在声明时必须指定其类型和本地初始化。初始化也可选择使用命名参数机制从父组件完成初始化。

装饰器使用说明

使用场景

装饰简单类型的变量 以下示例为@state装饰的简单类型,count被@state装饰成为状态变量,count的改变引起Button组件的刷新:

  1. 当状态变量count改变时,查询到只有Button组件关联了它;

  2. 执行Button组件的更新方法,实现按需刷新。

示例

点击修改姓名将会在张三,李四之间进行切换

点击修改年龄将会按照你设定的规则进行年龄的加减

当子组件上传参数的时候将使用子组件的参数

当没有的时候默认是父组件的数据

@Prop装饰器-父子单项同步

@Prop 装饰的变量可以和父组性建立单向的同步关系。@Prop装饰的变量是可变但是变化不会同步回其父组件。从API version 9开始,该装饰器支持在rkTS 卡中使用。

概述

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

  • @Prop变量允许在本地修改,但修改后的变化不会同步回父组件

  • 当父组件中的数据源更改时,与之相关的@Prop 装饰的变量都会自动更新。如果子组件已经在本地修改了@Prop 装饰的相关变量值,而在父组件中对应的@state装饰的变量被修改后,子组件本地修改的@Prop装饰的相关变量值将被覆盖

限制条件

  • @Prop 修饰复杂类型时是深拷贝,在拷贝的过程中除了基本类型、Map、Set、Date、Array 外,都会丢失类型。

  • @Prop装饰器不能在@Entry装饰的自定义组件中使用

装饰器使用规则说明

使用场景:

父组件@State 到子组件@Prop简单数据类型同步

以下示例是@state 到子组件@Prop 简单数据同步,父组件ParentComponent的状态变量 countDownstartValue 初始化子组件 CountDowncomponent 中eprop 装饰的 count,点击“Try again”,,count 的修改仅保留在 CountDownComponent不会同步给父组件ParentComponent。

ParentComponent的状态变量countDownstartValue 的变化将重冒CountDownComponent的count。

代码:

@Component
struct MyChid{
  @Prop
  age: number  =33
  private increase: number=1 //私有
  build(){
    Column(){
      if (this.age>=18){
        Text(`已经age成年了:${this.age}`).height(80)
      }else
      {
        Text(`age未成年了:${this.age}`).height(80)
      }
      Button('-修改子组件age').onClick(()=>{
        this.age-=this.increase
      })
        .height(80)
        .width(250)
        .margin(5)
    }
  }
}
​
@Entry
@Component
struct Myparent {
  @State
  init_age: number =16
​
  build(){
    Column(){
      Text(`父组件初始值:${this.init_age}`).height(80)
​
      Button('+修改父组件age').onClick(()=>{
        this.init_age+=1
      })
        .height(80)
        .margin(5)
        .width(250)
​
      Divider()
      MyChid({age:this.init_age,increase:2})
    }
  }
}

@Link装饰器-父子双向同步

子组件中被@Link 装饰的变量与其父组件中对应的数据源建立双向数据绑定。从APIversion 9开始,该装饰器支持在ArkTS卡片中使用。

需要注意:@Link 装饰的变量与其父组件中的数据源共享相同的值。@Link 装饰器不能在@Entry 装饰的自定义组件中使用。

代码示例展示:

//自定义按钮的信息类型
class ButtonState{
  value:string;
  width:number=0;
​
  constructor(value:string, width:number){
    this.value = value;
    this.width = width;
  }
}
​
​
@Component
​
struct MyChildGreenButton{
  //拥有 绿色按钮的组件,Link装饰器 实现双向同步
  @Link
  buttonState:ButtonState   //自定义对象类型
​
  build(){
      Button(`${this.buttonState.value}`)
        .width(this.buttonState.width)
        .height(150)
        .backgroundColor(Color.Green)
        .onClick(()=>{
          //点击按钮  实现宽度的变化
          if(this.buttonState.width<700){
            this.buttonState.width+=100
          }else {
            //按钮宽度回到初始值
            this.buttonState = new ButtonState('绿色按钮',100)
          }
        })
  }
}
​
​
@Component
struct MyChildRedButton{
  //拥有 红色按钮的组件,Link装饰器 实现双向同步
  @Link
  value: string
  @Link
  buttomWidth: number;
​
  build(){
    Button(`${this.value}`)
      .width(this.buttomWidth)
      .height(150)
      .backgroundColor(Color.Red)
      .onClick(()=>{
        //点击按钮  实现宽度的变化
        if(this.buttomWidth<700){
          this.buttomWidth+=100
        }else {
          //按钮宽度回到初始值
          this.buttomWidth = 100
        }
      })
  }
}
​
@Entry
@Component
struct MYParent{
  @State parentGreenButton:ButtonState=new ButtonState('一号',100)  //状态变量
  @State parentRedValue: string = '二号子组件'  //状态变量
  @State parentRedWidth: number = 200   //状态变量  //绿色按钮的宽度
​
  build(){
     Column(){
       //父组件中调整按钮宽度
       Button(`父组件中修改绿色按钮的宽度:${this.parentGreenButton.width}`)
         .onClick(()=>{
           this.parentGreenButton.width = this.parentGreenButton.width < 700 ? this.parentGreenButton.width+100:100
         })
​
       Button(`父组件中修改红色按钮的宽度:${this.parentRedWidth}`)
         .onClick(()=>{
           this.parentRedWidth = this.parentRedWidth < 700 ? this.parentRedWidth+100:100
         })
​
       Divider()
​
       MyChildGreenButton({buttonState:$parentGreenButton})  //传递Link装饰器的变量时候加 $ 符号
       MyChildRedButton({value:$parentRedValue,buttomWidth:$parentRedWidth})
     }
  }
}

if/else 条件渲染

ArkTS 提供了渲染控制的能力。条件渲染可根据应用的不同状态,使用if、else 和else if 渲染对应状态下的UI内容。从API version 9开始,该接口支持在 ArkTS卡片中使用。

使用规则

  • 支持if、else和else if 语句。

  • if、else if 后跟随的条件语句可以使用状态变量

  • 允许在容器组件内使用,通过条件渲染语句构建不同的子组件。

  • 条件渲染语句在涉及到组件的父子关系时是“透明”的,当父组件和子组件之间存在一个或多个if语句时,必须遵守父组件关于子组件使用的规则。

  • “每个分支内部的构建函数必须遵循构建函数的规则,并创建一个或多个组件。无法创建组件的空构建函数会产生语法错误。

  • 某些容器组件限制子组件的类型或数量,将条件渲染语句用于这些组件内时,这些限制将同样应用于条件渲染语句内创建的组件。例如,Grid容器组件的子组件仅支持GridItem 组件,在Grid 内使用条件渲染语句时,条件渲染语句内仅允许使用GridItem组件

更新机制

当if、else if 后跟随的状态判断中使用的状态变量值变化时,条件渲染语句会进行更新,更新步骤如下:

  1. 评估if和else if的状态判断条件,如果分支没有变化,请无需执行以下步骤。如果分支有变化,则执行2、3步骤:

  2. 删除此前构建的所有子组件。

  3. 执行新分支的构造函数,将获取到的组件添加到if 父容器中。如果缺少适用的 else分支,则不构建任何内容。

    条件可以包括 Typescript 表达式。对于构造函数中的表达式,此类表达式不得更改应用程序状态。

使用if进行条件渲染

if 语句的每个分支都包含一个构建函数。此类构建函数必须创建一个或多个子组件。在初始渲染时,if语句会执行构建函数,并将生成的子组件添加到其父组件中。

“每当if或else if条件语句中使用的状态变量发生变化时,条件语句都会更新并重新评估新的条件值。如果条件值评估发生了变化,这意味着需要构建另一个条件分支。此时ArkUI 框架将:

  1. 删除所有以前渲染的(早期分支的)组件。

  2. 执行新分支的构造函数,将生成的子组件添加到其父组件中

代码演示

分为两种 :第一种 点击“是否真假的按钮的时候” 计数器的值会归零

//定义子组件
@Component
struct MyChild{
​
  //计数器
  @State   counter:number=0
  label: string;
​
  build(){
    Row(){
      Text(`${this.label}`)
        .width(100)
        .height(100)
        .fontSize(20)
​
​
      Button(`计数器的值:${this.counter}`)
        .width(200)
        .height(60)
        .onClick(()=>{
           this.counter += 1;
        })
    }
  }
}
​
@Entry
@Component
struct MyParent{
  @State flag:boolean=false;
  build(){
    Column(){
      //根据判断决定子组件
      if(this.flag){
        MyChild({label:'zhenzhen'})
      }else {
        MyChild({label:'jiajia'})
      }
      Divider()
      Button(`是否真假:${this.flag}`)
        .width(300)
        .height(60)
        .fontSize(30)
        .margin(40)
        .onClick(()=>{
          this.flag=!this.flag
        })
    }
  }
}

第二种 点击是否真假的时候计数器的值不会进行更新归零

//定义子组件
@Component
struct MyChild{
​
  //计数器
  @Link counter:number;
  label: string;
​
  build(){
    Row(){
      Text(`${this.label}`)
        .width(100)
        .height(100)
        .fontSize(20)
​
​
      Button(`计数器的值:${this.counter}`)
        .width(200)
        .height(60)
        .onClick(()=>{
           this.counter += 1;
        })
    }
  }
}
​
​
@Entry
@Component
struct MyParent{
  @State flag:boolean=false;
  @State parentCount: number=0
  build(){
    Column(){
      //根据判断决定子组件
      if(this.flag){
        MyChild({counter:$parentCount,label:'zhenzhen'})
      }else {
        MyChild({counter:$parentCount,label:'jiajia'})
      }
      Divider()
      Button(`是否真假:${this.flag}`)
        .width(300)
        .height(60)
        .fontSize(30)
        .margin(40)
        .onClick(()=>{
          this.flag=!this.flag
        })
    }
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/672902.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网页安全登陆的设计思路

对于Web网站来讲,不管是企业内容信息化系统,还是公共站点(博客、音视频站等),都有需要用户注册和登录的功能。用以识别用户、信息交互、信息隔离以及商业行为等场景。用户数据已成为网站的重要资产。保护用户信息(数据)是网站安全运行的关键任务。本文以用户安全登录的场…

AI产品导航站

1、AI产品导航站 (chat2ai.cn)

自然语言处理(NLP)—— 神经网络语言处理

1. 总体原则 1.1 深度神经网络&#xff08;Deep Neural Network&#xff09;的训练过程 下图展示了自然语言处理&#xff08;NLP&#xff09;领域内使用的深度神经网络&#xff08;Deep Neural Network&#xff09;的训练过程的简化图。 在神经网络的NLP领域&#xff1a; 语料…

mybatis异常:Invalid bound statement (not found): com.lm.mapper.ArticleMapper.list

现象&#xff1a; 原因&#xff1a; 无效绑定&#xff0c;应该是mybatis最常见的一个异常了&#xff0c;接口与XML文件没绑定。首先&#xff0c;mapper接口并没有实现类&#xff0c;所以框架会通过JDK动态代理代理模式获取接口的代理实现类&#xff0c;进而根据接口全限定类名…

高清矩阵是什么?

在数学中&#xff0c;矩阵是一个按照长方阵列排列的复数或实数集合&#xff0c;最早来自于方程组的系数及常数所构成的方阵。如图为m行n列的矩阵&#xff1a; 由此延伸可以想到矩阵图片是把一个三维空间分切成多个行和列的区域进行图像捕获&#xff0c;将捕获图像再进行拼合成为…

C51学习归纳1 --- led点亮、led闪烁、led流水灯

第一节主要是针对LED的控制学习。这个过程中我们需要掌握的&#xff1a;1、控制的实现方法&#xff0c;控制实现的方法在后续的学习中是通用的。2、如何知道谁控制谁&#xff0c;通过查找开发板原理图获取&#xff0c;原理图的阅读的能力&#xff0c;在日后也是非常常用的。 一…

PySide6在VScode中提示:vscode module not found error: no module named ‘pyside6‘解决方案

最近在B站学习PySide6&#xff1a;PySide6百炼成真&#xff0c;带你系统性入门Qt https://www.bilibili.com/video/BV1c84y1N7iL?p3&vd_source256724e7f8bba144c62a17f9fa758a04 学习到第3节&#xff1a;003基础框架 003基础框架 from PySide6.QtWidgets import QApplicat…

小白也能看得懂的基于HTML+CSS+JS实现的五子棋小游戏

五子棋是一种起源于中国的传统棋类游戏&#xff0c;具有悠久的历史。 基本规则 棋盘&#xff1a; 五子棋通常在一个 15x15 的棋盘上进行&#xff0c;但也可以在更大的棋盘上进行。棋盘上的每个交叉点称为一个“点”。 棋子&#xff1a; 五子棋使用黑白两色的棋子。两名玩家分别…

44-3 waf绕过 - WAF绕过方法

环境准备: 43-5 waf绕过 - 安全狗简介及安装-CSDN博客然后在安装pikachu靶场:构建完善的安全渗透测试环境:推荐工具、资源和下载链接_渗透测试靶机下载-CSDN博客一、首先验证云WAF是否存在于靶场(老师的靶场是部署在阿里云) 靶场地址:http://127.0.0.1/pikachu-master/v…

追寻美的指引--纪念西蒙斯

周六早上醒来&#xff0c;James Simons&#xff08;西蒙斯&#xff09;辞世的消息刷屏了。多数人知道他&#xff0c;是因为他的财富和量化对冲基金公司-文艺复兴。但他更值得为人纪念的身份&#xff0c;则是数学家和慈善家。 西蒙斯1938年生于麻省&#xff0c;毕业于MIT&#…

1.JAVA小项目(零钱通)

一、说明 博客内容&#xff1a;B站韩顺平老师的视频&#xff0c;以及代码的整理。此项目分为两个版本&#xff1a; 面向过程思路实现面向对象思路实现 韩老师视频地址&#xff1a;【【零基础 快速学Java】韩顺平 零基础30天学会Java】 https://www.bilibili.com/video/BV1fh4…

Java大文件上传、分片上传、多文件上传、断点续传、上传文件minio、分片上传minio等解决方案

一、上传说明 文件上传花样百出&#xff0c;根据不同场景使用不同方案进行实现尤为必要。通常开发过程中&#xff0c;文件较小&#xff0c;直接将文件转化为字节流上传到服务器&#xff0c;但是文件较大时&#xff0c;用普通的方法上传&#xff0c;显然效果不是很好&#xff0c…

nginx的配置粗记

小白nginx的配置随笔&#xff08;随便记记&#xff09; 前言 我们都知道nginx有很多用途&#xff0c;比如&#xff1a;负载均衡&#xff0c;反向代理&#xff0c;网关路由&#xff0c;解决跨域等问题。我这次开发项目&#xff0c;用到的一些功能也涉及到了对nginx的配置&#…

Spark介绍及RDD操作

Spark介绍及RDD操作 PySpark简介spark特点运行原理spark实例化 SparkCore-RDDRDD创建转换&#xff08;Transformation&#xff09;行动&#xff08;Action&#xff09; PySpark简介 spark特点 运行速度快&#xff1a;DAG内存运算容易使用&#xff1a;Java、Scala、Python、R通…

Kubernetes——YAML文件编写

目录 一、创建Kubernetes对象YAML文件必备字段 1.apiVersion 2.kind 3.metadata 4.spec 二、YAML格式基本规范 1.结构表示 2.键值对 3.列表&#xff08;数组&#xff09; 4.字典&#xff08;映射&#xff09; 5.数据类型 6.注释 7.多文档支持 8.复杂结构 9.示例 …

快速排序与归并排序(非递归)

目录 快速排序&#xff08;双指针法&#xff09; 原理 代码 快速排序&#xff08;非递归&#xff09; 原理 代码 归并排序 介绍 优点 缺点 图片 原理 代码 归并排序&#xff08;非递归&#xff09; 代码 快速排序&#xff08;双指针法&#xff09; 快速排序的精…

【讲解下常见的分类算法,什么是分类算法?】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

redis如何实现分布式锁

Redisson是怎么实现分布式锁的 分布式锁&#xff1a;Redisson 提供了一种简单而强大的方式来实现分布式锁。 它支持多种锁模式&#xff0c;如公平锁、可重入锁、读写锁等&#xff0c;并且提供了锁的超时设置和自动释放功能。 锁的获取 在Redisson中常见获取锁的方式有 lock() …

面向对象概述

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 面向对象&#xff08;Object Oriented&#xff09;的英文缩写是OO&#xff0c;它是一种设计思想。从20世纪60年代提出面向对象的概念到现在&#xff…

Cyber Weekly #9

赛博新闻 1、OpenAI&#xff1a;GPTs向全部用户开放&#xff0c;使用GPT-4o OpenAI宣布所有ChatGPT免费用户现在可以在GPT商店中使用GPTs&#xff0c;并且这些GPTs现在使用最新的GPT-4o模型。 2、马斯克 vs. Yann LeCun 这一周&#xff0c;AI圈最热闹的莫过于马斯克和LeCun的…