上海专业网站建设服,响应式布局实现,编写网站,浦江县建设局网站目录
一、State装饰器
二、自定义组件
三、Prop和Link、Provide和Consume
四、Observed和ObjectLink 一、State装饰器 这里涉及到两个概念 状态 和 视图
状态#xff08;State#xff09;#xff1a;指驱动视图更新的数据#xff08;就是被State注解标记的变量State装饰器
二、自定义组件
三、Prop和Link、Provide和Consume
四、Observed和ObjectLink 一、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直接去传递参数。 四、Observed和ObjectLink 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 Monaconsole.log(对象内部嵌套的对象的属性已经发生了改变);})}
}Observed
class Person{name:stringage:numbergf:Personconstructor(name: string, age: number, gf ?: Person) {this.name name;this.age age;this.gf gf;}
}