ArkUI - 状态管理

news/2024/11/15 0:07:24/

目录

一、@State装饰器 

二、自定义组件

三、@Prop和@Link、@Provide和@Consume


一、@State装饰器 

这里涉及到两个概念 状态 视图 

  • 状态(State):指驱动视图更新的数据(就是被@State注解标记的变量)
  • 视图(View):基于UI描述渲染的得到的用户界面

简单来说,就是被@State修饰的变量如果在视图中被互动事件修改了,如果别的地方要是用到了这个变量也会同时被修改。但如果只是一个普通的变量的话视图里面不会发生任何变化(不过在底层里是被真正修改了的,只是不会触发视图更新渲染而已)。

注意:

1、@State装饰器标记的变量必须初始化,不能为空值,否则直接报错

2、@State装饰器不允许标记any、union这种复杂的类型

3、嵌套类型以及数组中的对象属性不能触发视图更新,如果真的需要实现这个情况,那么就要使用@Observed和ObjectLink注解,最后会讲到。


二、自定义组件

        ArkTS通过struct声明组件名,并通过@Component和@Entry装饰器,来构成一个自定义组件。使用@Entry和@Component装饰的自定义组件作为页面的入口,会在页面加载时首先进行渲染。

其实说白了就是把你写好的一个组件分模块封装起来,类似于Vue的组件

这里会涉及到三个注解,上一篇只是简单提及了一下

  • @Bulider:将组件封装为一个函数
  • @Extend():括号中写组件,这个是控制这个组件在这个项目中全局的样式
  • @Styles:这是将样式封装起来作为一函数

比如在这个页面中,每一个待办项其实都是相同的,复用性极高,我们可以将这个组件单独提取出来然后多次复用。

其次就是每个待办项有两种渲染状态,完成以及待办

先来看看这个部分的代码

可以看出这两个Image的实现具有大量重复代码,也就图片参数不一样,这两个图片可以在鸿蒙官网上直接下载然后放在media文件里。

最后强调一次$r("app.xxx")是查找本地资源,app是默认前缀必须携带。

@Bulider装饰器可以将组件直接封装在函数里面多次调用。

现在我们使用@Bulider将这部分重复的逻辑封装起来,然后用@Styles和@Extend将样式也封装起来。

@Component
export struct ToDoItem {@State private finished: boolean = false;private content: string = "新任务";build() {Row() {this.card(this.content)}.cardStyle().onClick(() => {this.finished = !this.finished})}@Builder card(content: string) {if (!this.finished) {Image($r("app.media.ic_screenshot_circle")).ToDoImg()Text(content).margin({ left: 20 })} else {Image($r("app.media.ic_public_todo_filled")).ToDoImg()Text(content).finishedToDo()}}@Styles cardStyle() {.backgroundColor(Color.White).width("95%").padding(20).borderRadius(15).shadow({ radius: 6, color: "#36D", offsetX: 2, offsetY: 4 }).margin(10)}
}@Extend(Text) function finishedToDo() {.margin({ left: 20 }).decoration({ type: TextDecorationType.LineThrough }).fontColor('#B1B2B1')
}@Extend(Image) function ToDoImg() {.width(20).borderRadius(10).interpolation(ImageInterpolation.High)
}

这样一个自定义组件就完成了

注意:

1、@Builder与@Styles写在struct的外面里面都可以,不过@Extent只能写在struct外面

2、如果要写在struct外面,就要像Extent一样在名字前加上function关键字

然后在另一个组件中调用,这样的话,ToDoList就是父组件了,相对的其调用的ToDoItem就是子组件

import { ToDoItem } from '../TODO/ToDoItem'
@Entry
@Component
struct  ToDoList{build(){Column(){ToDoItem({content:"An1ong"})ToDoItem({content:"完成啦!"})}}
}

效果 

 

是不是感觉代码一下子就整洁规范起来了。你也可以使用之前学到的List和ListItem,以及一些组件优化这个页面。


三、@Prop和@Link、@Provide和@Consume

父子组件之间需要数据同步时,可以使用@Porp和@Link装饰器

啥是父子组件呢?就比如我们刚才的ToDoList案例中,我们将每一个ToDoItem分离了出来,然后在总体的Entry入口ToDoList中调用,这就是父子组件。如果在父组件定义了一个变量,在子组件中是无法直接调用获取的(当然你专门写个方法传递也是可以的)

这两个注解的区别是:

单向传递意思就是父组件将数据传递给子组件之后,子组件的这个数据发生改变时不会导致父组件的视图刷新。而双向同步之后子组件的这个数据发生变化之后就会同步给父组件导致视图刷新。

再以我们刚才的ToDoList案例举例,现在要实现点击子组件完成任务并同步至视图

父组件中传递参数时要使用 $ 变量 的这种格式才能传递

 子组件中就要使用@Link修饰并且不能初始化一个值了

至于@Provide和@Consume,这个是用来跨组件使用的。比如@Link和@Prop是父子关系使用,而@Provide和@Consume就不只是父子关系了,你可以多层关系使用,爷孙组件,祖宗和祖孙组件直接使用。

而且使用也不用自己传递参数了,就比如把这个案例中修改为@Provide和@Consume就需要做一些小小的修改

父组件中使用@Provide代替@State,并且调用子组件时不需要传递被修饰的变量

 子组件中将@Link改为@Consume

 

可以达到同样的效果,并且看起来更方便了,不需要自己去传递参数也不用考虑跨了多少组件的问题

那么,古尔丹,代价是什么呢? 

本来直接传递就行了,现在又要在底层帮你维护。这样势必会造成大量的资源浪费。

所以除非是真的需要用到跨组件传递,否则只是父子组件的话还是尽量还是使用@Link直接去传递参数。


@ObjectLink和@Observed装饰器用于在涉及嵌套对象数组元素对象的场景中进行双向数据同步

@Observed修饰于对象类上

@ObjectLink修饰于变量

我们曾在一开始将@State的时候就说过,使用@State修饰的变量如果是嵌套类型以及数组中的对象属性的话就不能触发视图更新。

因此我们需要使用别的注解来解决这个问题

例如我现在有一个对象类Person

class Person{name:stringage:numbergirlFriend:Personconstructor(name: string, age: number, girlFriend ?: Person) {this.name = name;this.age = age;this.girlFriend = girlFriend;}
}

可以看到改变了对象内部嵌套的对象的属性被不会触发更新视图

因此使用方法为

在对象类上加上@Observed注解,然后创建一个新的组件,间接传入对象嵌套的那个对象作为参数

@Entry
@Component
struct Parent{@State p:Person = new Person('An1ong',21,new Person('KeQing',18))build(){Column(){Child({p:this.p.gf})}.width("100%").height("100%").justifyContent(FlexAlign.Center)}
}@Component
struct Child{@ObjectLink private p:Person;build(){Text(`${this.p.name} : ${this.p.age}`).fontSize(30).onClick(() => {this.p.name = "Mona"console.log("对象内部嵌套的对象的属性已经发生了改变");})}
}@Observed
class Person{name:stringage:numbergf:Personconstructor(name: string, age: number, gf ?: Person) {this.name = name;this.age = age;this.gf = gf;}
}


http://www.ppmy.cn/news/1279714.html

相关文章

《工具箱-SVN》SVN安装、备份、迁移教程

文章目录 一、服务器搭建SVN1.检查SVN是否存在2.安装SVN3.创建版本库4.创建版本库存放文件地址5.修改配置文件5.1 vim authz5.2 vim passwd5.3 vim svnserve.conf 6.启动并查看SVN7.SVN Checkout8.SVN Update9.SVN Commit 二、SVN-无法连接主机,目标计算机积极拒绝&…

hdfs.DataStreamer: Exception in createBlockOutputStream XXXXX

报错信息: java.io.IOException: Got error, statusERROR, status message , ack with firstBadLink as 192.168.100.13:9866at org.apache.hadoop.hdfs.protocol.datatransfer.DataTransferProtoUtil.checkBlockOpStatus(DataTransferProtoUtil.java:134)at org.a…

docker笔记1-安装与基础命令

docker的用途: 可以把应用程序代码及运行依赖环境打包成镜像,作为交付介质,在各种环境部署。可以将镜像(image)启动成容器(container),并提供多容器的生命周期进行管理(…

【零基础入门Docker】什么是Dockerfile Syntax

✍面向读者:所有人 ✍所属专栏:零基础入门Docker专栏https://blog.csdn.net/arthas777/category_12455882.html 目录 编写Dockerfile和Format的语法 2. MAINTAINER 3. RUN 4. ADD 6. ENTRYPOINT 7. CMD 8. EXPOSE 9. VOLUME 11. USER 12. ARG …

CentOS中docker安装及镜像源配置

1、首先配置docker的阿里yum源 cat >/etc/yum.repos.d/docker.repo<<EOF [docker-ce-edge] nameDocker CE Edge - \$basearch baseurlhttps://mirrors.aliyun.com/docker-ce/linux/centos/7/\$basearch/edge enabled1 gpgcheck1 gpgkeyhttps://mirrors.aliyun.com/do…

NVM(nodejs版本管理工具)下载以及设置国内代理

官方github GitHub - nvm-sh/nvm: Node Version Manager - POSIX-compliant bash script to manage multiple active node.js versions 配置代理 vim ~/.nvm/nvm.sh 添加: export NVM_NODEJS_ORG_MIRRORhttps://mirrors.aliyun.com/nodejs-release/安装node nvm install …

爬虫字典生成工具,CeWL使用教程

爬虫字典生成工具,CeWL使用教程 1.工具概述2.参数解析3.使用实例1.工具概述 CeWL 是一个 ruby 应用程序,它将给定的 URL 爬到指定的深度,可以选择跟随外部链接,并返回一个单词列表,然后可用于密码破解者 Cewl 是黑客武器库中的强大工具,因为它允许创建有针对性的单词列…

filebeat 7.10.2 当日志切割后,老的没采集完的,还会自动采集:

filebeat 7.10.2 当日志切割后,老的没采集完的,还会自动采集: [rootzz test]# stat tst.log* File: tst.log Size: 37485219 Blocks: 73216 IO Block: 4096 regular file Device: 803h/2051d Inode: 948699 Links: 1 Access: (0644/-rw-r--r--) Uid…