鸿蒙入门06-常见装饰器( 简单装饰器 )

news2024/11/25 0:28:28
  • 装饰器是鸿蒙开发中非常重要的一个环节
  • 因为在很多地方我们都需要用到装饰器
  • 并且如果我们想高度的复用, 那么装饰器就是必不可少的一环
  • 接下来我们就来介绍一些常见的装饰器
  • 注意 : 所有装饰器首字母大写

@Entry 

  • 用来装饰 struct 使用
  • 表示页面的入口

@Component 

  • 装饰 struct, 表示该 struct 具有基于组件的能力
  • 保证 struct 内部 包含一个且只能包含一个 build() 函数, 用于绘制 UI 界面
  • struct 内部, build() 函数外部, 用于存储数据的位置
  • 注意 : build() 函数内部必须要有容器组件
@Entry
@Component
struct Index {
  /* 这里存放数据 */
  build() {
    /* 这里构建 UI 界面 */
  }
}

 以上为基础内容结构

  • @Component 也可以单独定义组件
  • 单独定义的组件可以在其他组件内使用
@Entry
@Component
struct Index {
  /* 这里存放数据 */
  build() {
    /* 这里构建 UI 界面 */

    Row() {
      /* 可以直接使用子组件 */
      SonCom()
    }
  }
}

// 定义一个子组件
@Component
struct SonCom {
  build() {
    /* 这里构建子组件 UI 结构 */
  }
}

@State

  • 用来装饰变量的装饰器( 其实就是用于定义变量 )
  • 必须本地初始化数据, 支持通过构造函数赋值
  • 当 @State 定义的数据被修改的时候, 所在组件的 build() 方法会被重新调用, 重新绘制所在 UI 界面
@Entry
@Component
struct Index {
  /* 这里存放数据 */
  @State count: number = 0
  build() {
    /* 这里构建 UI 界面 */
    Column() {
      // 展示 @state 定义的变量
      Text(`${ this.count }`).fontSize(20)
      Divider().margin(10)
      // 按钮点击的时候修改 @state 定义的变量
      Button('Click Me').onClick(() => this.count++)
    }
  }
}

这里使用 Text() 组件展示了 @State 定义的 count 变量

通过 Button() 组件的点击事件修改了 @State 定义的 count 变量

因为变量的修改导致了 UI 界面的重新绘制

所以页面跟随出现变化

其实就是我们之前知道的响应式数据一个原理

  • 在子组件内也同样是使用 @State 定义数据
  • 在子组件内定义的数据, 可以通过父组件调用的时候进行赋值

 

@Entry
@Component
struct Index {
  /* 这里存放数据 */
  @State count: number = 0
  build() {
    /* 这里构建 UI 界面 */
    Column() {
      Text('父组件 UI 部分').fontSize(20)
      Text(`${ this.count }`).fontSize(20)
      Divider().margin(10)
      Button('Click Me').onClick(() => this.count++)

      Blank().height(30)
      Text('子组件 UI 部分')
      SonCom() // 不对初始内容进行赋值

      Blank().height(30)
      Text('子组件 UI 部分')
      SonCom({ count: 100 }) // 对初始内容进行赋值
    }
  }
}

@Component
struct SonCom {
  @State count: number = 0
  build() {
    Column() {
      Text(`${ this.count }`).fontSize(20)
    }
  }
}

当你调用子组件的时候

如果不对 @State 定义的变量赋值, 那么就用子组件内初始化时候的赋值

如果对 @State 定义的变量赋值, 那么就会使用调用时所赋予的值

  • 通过 @State 在子组件内进行赋值
  • 父子组件是互不干扰的, 数据是相互独立的
@Entry
@Component
struct Index {
  /* 这里存放数据 */
  @State count: number = 0
  build() {
    /* 这里构建 UI 界面 */
    Column() {
      Text('父组件 UI 部分').fontSize(20)
      Text(`${ this.count }`).fontSize(20)
      Divider().margin(10)
      Button('Click Me 修改父组件 count').onClick(() => this.count++)

      Blank().height(30)
      Text('子组件 UI 部分')
      SonCom()

    }
  }
}

@Component
struct SonCom {
  @State count: number = 0
  build() {
    Column() {
      Text(`${ this.count }`).fontSize(20)
      Divider().margin(10)
      Button('Click Me 修改子组件 count').onClick(() => this.count++)
    }
  }
}

@Prop

  • 继承了 @State 的所有功能
  • 注意 :
    • 定义的时候可以不需要本地直接初始化, 调用子组件的时候需要对其进行赋值
    • 被 @Prop 装饰的变量可以和父组件建立单向同步关系
    • @Prop 装饰的变量是可变的, 但是修改时不会同步回父组件, 当父组件的 @State 变化时, 本地修改的 @Prop 会被覆盖
@Entry
@Component
struct Index {
  /* 这里存放数据 */
  @State count: number = 0
  build() {
    /* 这里构建 UI 界面 */
    Column() {
      Text('父组件 UI 部分').fontSize(20)
      Text(`${ this.count }`).fontSize(20)
      Divider().margin(10)
      Button('Click Me 修改父组件 count').onClick(() => this.count++)

      Blank().height(30)
      Text('子组件 UI 部分')
      // 调用自组件的时候, 将父组件 @State 定义的 count 赋值
      SonCom({ count: this.count })
    }
  }
}

@Component
struct SonCom {
  // 使用 @Prop 定义一个初始变量
  @Prop count: number
  build() {
    Column() {
      Text(`${ this.count }`).fontSize(20)
      Divider().margin(10)
      Button('Click Me 修改子组件 count').onClick(() => this.count++)
    }
  }
}

  • 此时, 当你在子组件内修改 count 的时候, 子组件内的数据单独出现变换
  • 但是当你在父组件内修改 count 的时候, 会连带修改子组件内的 count, 并且会将覆盖子组件内的修改

@Link

  • @Link 装饰的变量和父组件会构建双向同步关系
    • 父组件会接受来自 @Link 装饰的变量的修改同步
    • 父组件的更新也会同步给 @Link 装饰的变量
  • @Link 装饰的变量与其父组件中的数据源共享相同的值
  • 注意 :
    • 子组件使用 @Link 定义变量的时候不需要赋值, 而是调用子组件的时候进行赋值
    • 调用子组件赋值的时候使用 "$变量名" 的形式进行赋值
    • @Link 装饰器不能再 @Entry 装饰的自定义组件中使用
@Entry
@Component
struct Index {
  /* 这里存放数据 */
  @State count: number = 0
  build() {
    /* 这里构建 UI 界面 */
    Column() {
      Text('父组件 UI 部分').fontSize(20)
      Text(`${ this.count }`).fontSize(20)
      Divider().margin(10)
      Button('Click Me 修改父组件 count').onClick(() => this.count++)

      Blank().height(30)
      Text('子组件 UI 部分')
      // 调用自组件的时候, 将父组件 @State 定义的 count 赋值
      // 注意: 使用 $变量名 的形式进行赋值
      SonCom({ count: $count })
    }
  }
}

@Component
struct SonCom {
  // 使用 @Link 定义一个初始变量
  @Link count: number
  build() {
    Column() {
      Text(`${ this.count }`).fontSize(20)
      Divider().margin(10)
      Button('Click Me 修改子组件 count').onClick(() => this.count++)
    }
  }
}

  • 此时, 子组件内修改 count 的时候, 会同步影响到父组件内的 count
  • 修改父组件内的 count 的时候, 也会同步影响到子组件内的 count

@Provide 和 @Consume

  • 之前我们学习过了 @State/@Link 两个装饰器组合在一起, 可以实现父子组件的双向数据传递
  • 如果在父子组件之间进行数据传递的话, 使用起来还是相当方便的
  • 但是, 如果层级过高的话, 那么使用起来就比较麻烦来
  • 我们先来看一下 @State/@Link 进行层级组件嵌套
@Entry
@Component
struct Index {
  /* 这里存放数据 */
  @State count: number = 0
  build() {
    Column() {
      Text('父组件 UI 部分').fontSize(20)
      Text(`${ this.count }`).fontSize(20)
      Divider().margin(10)
      Button('Click Me 修改父组件 count').onClick(() => this.count++)

      Blank().height(30)
      Text('子组件 UI 部分')
      // 调用子组件的时候, 将父组件 @State 定义的 count 赋值
      // 注意: 使用 $变量名 的形式进行赋值
      SonCom({ count: $count })
    }
  }
}

@Component
struct SonCom {
  // 使用 @Link 定义一个初始变量
  @Link count: number
  build() {
    Column() {
      Text(`${ this.count }`).fontSize(20)
      Divider().margin(10)
      Button('Click Me 修改子组件 count').onClick(() => this.count++)

      Blank().height(30)
      Text('子子组件 UI 部分')
      // 调用子子组件的时候, 将子组件 @Link 定义的 count 赋值
      // 注意: 使用 $变量名 的形式进行赋值
      SonSonCom({ count: $count })
    }
  }
}

@Component
struct SonSonCom {
  // 使用 @Link 定义一个初始变量
  @Link count: number
  build() {
    Column() {
      Text(`${ this.count }`).fontSize(20)
      Divider().margin(10)
      Button('Click Me 修改子组件 count').onClick(() => this.count++)
    }
  }
}

 

  • 此时我们就实现了跨组件传递数据
  • 但是想对来说就比较麻烦了, 相当繁琐
  • 如果组件嵌套的层级过深, 那么这个数据的传递就实在是太复杂了
  • 此时我们可以使用 @Provide 和 @Consume 进行跨组件数据传递
  • 使用语法 :
    • @Provide('名字') 变量名: 类型 = 赋值
    • @Consume('名字') 变量名
    • 注意 : @Provide 和 @Comsume 处使用的名字要一致, 但是变量名不需要一致

  • 使用发布订阅模式, 父类使用 @Provide, 其他需要观察的子类使用 @Consume, 就可以实现双向绑定
  • 当层级很深时, 不需要一层一层传递数据, 直接使用发布订阅进行监听就能实现相同的效果
  • @Provide 和 @Consume 可以通过相同的变量名或者相同的变量别名绑定, 但是变量类型必须相同
  • @Provide 必须设置初始值, @Consume 不可以设置默认初始值
  • @Provide 修饰的变量和 @Consume 修饰的变量可以是一对多的关系

@Watch

  • 使用观察者模式的装饰器
  • 注意 : 该装饰器不是触发变量变化, 而是绑定一个函数, 当监控的变量发生变化时, 该函数触发
  • 语法 : @Watch('函数名')
@Entry
@Component
struct Index {
  /* 这里存放数据 */
  // 在父组件内使用 @Provide 创建数据
  @State count: number = 0
  build() {
    Column() {
      Text('父组件 UI 部分').fontSize(20)
      Text(`${ this.count }`).fontSize(20)
      Divider().margin(10)
      Button('Click Me 修改父组件 count').onClick(() => this.count++)

      Blank().height(30)
      Text('子组件 UI 部分')
      SonCom({ count: this.count })
    }
  }
}

@Component
struct SonCom {
  @Prop @Watch('onCountUpdate') count: number

  onCountUpdate(): void {
    console.log('count 数据发生变化了')
  }
  build() {
    Column() {
      Text(`${ this.count }`).fontSize(20)
      Divider().margin(10)
      Button('Click Me 修改父组件 count').onClick(() => this.count++)
    }
  }
}

@Builder

  • @Builder 是 ArkUI 提供的一种更加轻量的复用机制
  • 因为在 @Component 内能且只能创建一个 build() 函数
  • 我们可以在组件内利用 @Builder 装饰器自定义一个构建函数
  • @Builder 创建的构建函数遵循 build() 函数的语法规则, 并且可以在 build() 函数内调用
  • 语法 :
    • 定义语法 : @Builder MyBuilder() {}
    • 使用语法 : this.MyBuilder() {}
  • 语法要点
    • 自定义构建函数可以在所属组件内的 build() 方法和其他自定义构建函数内调佣, 但不允许在组件外调用
    • 允许在自定义组件内定义一个或多个 @Builder 方法, 该方法被认为是该组件的私有成员
    • 在自定义函数体内, this 指代当前所属组件, 组件的状态变量可以在自定义构建函数内访问
    • 自定义构建函数不仅可以添加属性, 还可以添加事件

  • 在组件外也可以使用 @Builder 创建一个自定义构建函数
  • 注意 : 在组件外使用 @Builder 的时候, 构建函数内不能使用 this
@Entry
@Component
struct Index {
  /* 这里存放数据 */
  // 在父组件内使用 @Provide 创建数据
  @State count: number = 0

  // 创建一段组件内自定义构建函数
  @Builder CountUpdate() {
    Text('父组件 UI 部分').fontSize(20)
    Text(`${ this.count }`).fontSize(20)
    Divider().margin(10)
    Button('Click Me 修改父组件 count').onClick(() => this.count++)
  }

  build() {
    Column() {
      // 直接使用自定义构建函数
      this.CountUpdate()

      Blank().height(30)

      // 使用组件外自定义构建函数
      MyBuilder('Hello World')
    }
  }
}

// 组件外定义自定义构建函数
@Builder
function MyBuilder(message: string) {
  Column() {
    Text(message)
  }
}

@Styles

  • 在开发中有的时候, 有的时候我们的一些样式也要重用
  • @Styles 装饰器就可以将多条样式提炼成一个方法, 以供复用
  • 和 @Builder 一样, 可以定义在 组件内 和 组件外
@Entry
@Component
struct Index {
  // 定义一个组件内样式方法
  @Styles MyStyles() {
    .width(200)
    .height(200)
    .backgroundColor(Color.Orange)
  }

  build() {
    Column() {
      Row() {}.MyStyles()

      Blank().margin(10)

      Row() {}.MyStyles()
    }
  }
}

  • 这是组件内定义样式方法
  • 我们再来定义一个组件外样式方法
@Entry
@Component
struct Index {
  // 定义一个组件内样式方法
  @Styles MyStyles() {
    .width(200)
    .height(200)
    .backgroundColor(Color.Orange)
  }

  build() {
    Column() {
      Row() {}.MyStyles()

      Blank().margin(10)

      Row() {}.MyStyles2()
    }
  }
}

@Styles
function MyStyles2() {
  .width(100)
  .height(100)
  .backgroundColor(Color.Pink)
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL中如何随机获取一条记录

点击上方蓝字关注我 随机获取一条记录是在数据库查询中常见的需求,特别在需要展示随机内容或者随机推荐的场景下。在 MySQL 中,有多种方法可以实现随机获取一条记录,每种方法都有其适用的情况和性能特点。在本文中,我们将探讨几种…

实测52.4MB/s!全志T3+FPGA的CSI通信案例分享!

CSI总线介绍与优势 CSI(CMOS sensor parallel interfaces)总线是一种用于连接图像传感器和处理器的并行通信接口,应用于工业自动化、能源电力、智慧医疗等领域,CSI总线接口示意图如下所示(以全志科技T3处理器的CSI0为…

【运输层】TCP 的流量控制和拥塞控制

目录 1、流量控制 2、TCP 的拥塞控制 (1)拥塞控制的原理 (2)拥塞控制的具体方法 1、流量控制 一般说来,我们总是希望数据传输得更快一些。但如果发送方把数据发送得过快,接收方就可能来不及接收&#x…

Simba:Mamba 增强了 U-ShiftGCN,用于视频中的骨骼动作识别

Simba:Mamba 增强了 U-ShiftGCN,用于视频中的骨骼动作识别 摘要IntroductionRelated WorksMethodologyDown-sampling ShiftGCN Encoder Experiments & ResultsDatasets Simba: Mamba augmented U-ShiftGCN for Skeletal Action Recognition in Video…

计算机网络 -- 网络编程基础

一 学习准备 1.1 IP地址 在 前文中我们提到过: IP 是全球网络的基础,使用 IP 地址来标识公网环境下主机的唯一性,我们可以根据 目的IP地址 进行跨路由器的远端通信。 但是我们也提到了,通过 IP 地址,只能寻找到目标主机&#xff…

视频质量度量VQM算法详细介绍

视频质量评价 视频质量评价(Video Quality Assessment,VQA)是指通过主观、客观的方式对视频图像的内容、画质等,进行感知、衡量与评价。 ITU definations subjective assessment: the determination of the quality or impairment of programme-like pictures presented…

最新UI发卡盗U,支持多语言,更新UI界面,支持多个主流钱包,附带系统搭建教程

环境:Linux系统 进入宝塔安装环境:Nginx 1.22.1 MySQL 8.0 php7.4 phpMyAdmin 5.2 按照说明去安装环境,如果没有找到MySQL8.0版本去"软件商店"搜索Mysql切换至8.0 1.上传开源源码 2.上传数据库文件 3.上传猴导入数据库文件 4.修…

Flask 解决指定端口无法生效问题

问题重现 手动指定的IP端口是app.run(host0.0.0.0, port9304),但是启动的地址显示的却是http://127.0.0.1:5000。 if __name__ __main__:app.run(host0.0.0.0, port9304)启动地址如下: 解决方案 PyCharm会自动识别出来flask项目(即使你…

.Net RabbitMQ(消息队列)

文章目录 一.RabbitMQ 介绍以及工作模式1.RabbitMQ的介绍:2.RabbitMQ的工作模式: 二.RabbitMQ安装1.安装Erlang语言环境2.安装RabbitMQ 三.在.Net中使用RabbitMQ1.HelloWorld模式2.工作队列模式3.发布订阅模式4.Routing路由模式和Topics通配符模式 一.Ra…

114 接口中幂等性的保证

前言 同样是 面试问题 如何确保接口的 幂等性 幂等是一个 较为抽象的概念, 多次重复访问, 不会导致业务逻辑的异常 这里从增删改查, 几个方面列一下 一般来说, 我们核心需要关注的就是 新增 和 更新 对于 增加元素, 首先针对唯一约束进行校验, 然后再处理新增的相关业…

IDEA中Docker相关操作的使用教程

一、引言 Docker作为当前最流行的容器化技术,极大地简化了应用的部署和管理。而IntelliJ IDEA作为一款强大的集成开发环境,也提供了对Docker的集成支持。本文将介绍如何在IDEA中配置和使用Docker,包括远程访问配置、服务连接、Dockerfile编写…

【Linux冯诺依曼体系结构】

目录 1.冯诺依曼体系结构原理 1.冯诺依曼体系结构 我们常见的计算机,如笔记本。我们不常见的计算机,如服务器,大部分都遵守冯诺依曼体系。 截至目前,我们所认识的计算机,都是有一个个的硬件组件组成 输入单元&#…

HTML学习笔记:(一)基础方法

Html格式 里面文件使用平台为&#xff1a;w3school 1、基础功能&#xff1a; <html><head> <title>这是我的第一个html页面,会显示在浏览器的标题栏中</title> </head> <!--修改背景颜色 --> <body bgcolor"yellow"> …

如何合理利用多个中国大陆小带宽服务器?

我们知道在中国大陆带宽单价非常昂贵&#xff0c;一个1Mbps 带宽的机子一年就得卖好几百人民币&#xff0c;这是不值当的&#xff0c;当然我们可以去低价漂阿里云、腾讯云的轻量服务器&#xff0c;99包年&#xff0c;但是带宽太小很难崩。 所以&#xff0c;我们必须构建一个能够…

钉钉直播回放怎么下载到本地

钉钉直播回放如何下载到本地,本文就给大家解密如何下载到本地 工具我已经给大家打包好了 钉钉直播回放下载软件链接&#xff1a;https://pan.baidu.com/s/1_4NZLfENDxswI2ANsQVvpw?pwd1234 提取码&#xff1a;1234 --来自百度网盘超级会员V10的分享 1.首先解压好我给大家…

使用脚本启动和关闭微服务

使用脚本启动和关闭微服务 一、前言二、启动1、处理每个服务2、编写启动脚本3、其他启动脚本&#xff08;无效&#xff0c;有兴趣可以看看&#xff09;4、启动 三、关闭1、测试拿服务进程id的命令是否正确2、编写关闭脚本3、关闭 一、前言 假如在服务器中部署微服务不使用 doc…

ElasticSearch:基础操作

一、ES的概念及使用场景 ElasticSearch是一个分布式&#xff0c;高性能、高可用、可伸缩、RESTful 风格的搜索和数据分析引擎。通常作为Elastic Stack的核心来使用 我们通过将ES 和 mysql对比来更好的理解 ES&#xff0c;ES和mysql相关的基本概念的对比表格如下&#xff1a; …

从Linux角度具体理解程序翻译过程-----预处理、编译、汇编、链接

前言&#xff1a; 在C语言中&#xff0c;我们知道程序从我们所写的代码到可执行执行的过程中经历了以下过程 1.预处理 2.编译 3.汇编 4.链接 可以通过下图来理解 翻译过程 1.预处理 该过程主要进行以下操作&#xff1a; (1)头文件的包含 (2)define定义符号的替换&#xff…

稀碎从零算法笔记Day52-LeetCode:从双倍数组中还原原数组

题型&#xff1a;数组、贪心 链接&#xff1a;2007. 从双倍数组中还原原数组 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 题目描述 一个整数数组 original 可以转变成一个 双倍 数组 changed &#xff0c;转变方式为将 original 中每个元素 值乘以 …

EFK架构部署

7.17版本 准备工作 配置域名 cat >> /etc/hosts <<EOF 192.168.199.149 elk149daidaiedu.com 192.168.199.150 elk150daidaiedu.com 192.168.199.155 elk155daidaiedu.com EOF 修改主机名 hostnamectl set-hostname elk155.daidaiedu.com 免密登录 ssh-keyge…