@Link双向绑定和@Provide、Consume跨层传递、@Observed&@ObjectLink更改多层结构的数据
@Link 双向同步
使用 @Link 可以实现父组件和子组件的双向同步
使用步骤:
1.将父组件的状态属性传递给子组件
2.子组件通过@Link修饰即可
基本数据类型和复杂数据类型都是可以的哈
@Link双向绑定
@Component
struct Child {
// 使用Link修饰的,说明这个是双向的。
// 子组件的修改会同步到父组件中去
@Link sonValue:string
build() {
Column(){
Text('我是子组件')
Text('子组件的数据是:'+this.sonValue)
Button('子组件修改数据').onClick(()=>{
this.sonValue = '完美世界'
})
}.backgroundColor("#cdc").width('100%')
}
}
@Entry
@Component
struct Index {
@State contValue:string = '仙逆'
build() {
Column(){
Row(){
Button('修改数据').onClick(()=>{
})
}
Row(){
Text('父组件的数据:')
Text(this.contValue)
}.backgroundColor('#cac').width('100%').height(50).margin({bottom:30})
Child({
sonValue: this.contValue
})
}
}
}

@Provide和@Consume的简单介绍
父组件使用@Provide修饰声明的变量。
中间无论有多少层级,孙子组件都可以通过@Consume来获取到。
中间层不需要对数据做任何的处理。
父组件更改的数据孙子组件会接收并且会更新界面。
同理孙子组件更改数据爷爷组件也会接收并且更新界面。
也就是说: @Provide和@Consume是双向的,数据变化后界面会自动更新视图
需要注意的是:使用@Provide和@Consume生命的变量名必须是一样的
使用办法
1.将父组件的状态属性使用 @Provide 修饰,变量名称必须和@Consume保持一致
2.子组件通过 @Consume 修饰,变量名称必须和@Provide保持一致
基本数据类型和复杂数据类型都是可以的哈
@Provide和@Consume传递数据并且双向更改
@Component
struct SonComponent {
// 这个子组件不需要对数据做任何的处理
build() {
Column(){
Button('子组件修改数据').onClick(()=>{
})
Text('子组件的数据是:').backgroundColor('#cdc').width('100%').height(50).margin({bottom:30})
SunComponent()
}
}
}
@Component
struct SunComponent {
// 使用 @Consume 接收数据。和@Provide声明的必须是同一个变量名。
@Consume nickName:string
build() {
Column(){
// 孙子组件更新数据后,爷爷组件也会更新的
Button('孙子组件修改数据').onClick(()=>{
this.nickName = '孙子组件更改了数据'
})
Text('我是孙子组件数据是:'+this.nickName).backgroundColor('#cee').width('100%').height(50).margin({bottom:30})
}
}
}
@Entry
@Component
struct Index {
// 顶级组件使用
@State contValue:string = '仙逆'
@Provide nickName:string='我的div丢了怎么办?'
build() {
Column(){
Row(){
Button('父组件修改数据').onClick(()=>{
this.nickName = '我的昵称哈哈哈'
})
}
Row(){
Text('父组件的数据:')
Text(this.nickName)
}.backgroundColor('#cac').width('100%').height(50).margin({bottom:30})
SonComponent()
}
}
}


@Observed 、 @ObjectLink 嵌套对象数组属性变化
说明:装饰器仅能观察到第一层的变化。对于多层嵌套的情况,比如对象数组等。
第2层属性的变化是无法观察到的,这个时候,我们的主角就出现了。
@Observed/@ObjectLink装饰器
作用:用于在涉及嵌套对象或数组的场景中进行双向数据同步
需要注意:@ObjectLink修饰符不能用在 Entry 修饰的组件中使用
@Observed 修饰的必须是使用类进行实例化的
使用步骤
1,使用@Observed去修饰类声明的数据
2,在子组件中使用@ObjectLink去修饰要更改的数据
interface PersonList{
name:string
id:string
age:number
}
// 将数据用类的方式进行实例化,而不能用接口的方式进行。因为:@Observed修饰时必须是使用类进行初始
@Observed
class Person{
name:string
id:string
age:number
constructor(obj:PersonList) {
this.name = obj.name
this.id = obj.id
this.age = obj.age
}
}
@Component
struct ChildCom {
// 在子组件的中使用@ObjectLink
@ObjectLink itemObj:Person
// 等会父组件会重写这个方法
editorHandler = ()=>{}
build() {
Column(){
Row(){
Text('姓名1:'+ this.itemObj.name).margin({right:20})
Text('年龄:'+ this.itemObj.age).margin({right:20})
Button('修改').onClick(()=>{
this.editorHandler()
})
}.height(70).backgroundColor('#cac').width('100%').margin({bottom:10}).padding({left:10, right:10})
}
}
}
@Entry
@Component
struct Index {
@State PersonArray:PersonList[]=[
new Person({
name:'张三',
id:'user01',
age:19
}),
new Person({
name:'李四',
id:'user02',
age:22
})
]
build() {
Column(){
ForEach(this.PersonArray,(item:Person,index:number)=>{
ChildCom({
itemObj: item,
// 我们现在就可以更改第层的属性了,父组件进行更改
editorHandler:()=>{
item.age++
}
})
})
}
}
}

刚刚我们讲了,是通过父组件中的方法来进行更改的。
其实你也可以通过子组件来更新。但是我们一般不这样进行更改。
下面我们来看下,直接在子组件中进行修改。
...其他省略...
@Component
struct ChildCom {
// 在子组件的中使用@ObjectLink
@ObjectLink itemObj:Person
build() {
Column(){
Row(){
Text('姓名1:'+ this.itemObj.name).margin({right:20})
Text('年龄:'+ this.itemObj.age).margin({right:20})
Button('修改').onClick(()=>{
// 直接在子组件中进行修改
this.itemObj.age++
})
}.height(70).backgroundColor('#cac').width('100%').margin({bottom:10}).padding({left:10, right:10})
}
}
}
...其他省略...

@Observed&@ObjectLink更新的逻辑
属性更新的逻辑:当我们使用@0bserved装饰过的数据,属性改变时,
就会监听到遍历依赖它的 @0bjectLink 包装类,通知数据更新。
请看下面这个例子
... 其他代码不变
@Entry
@Component
struct Index {
build() {
Column() {
// 属性更新的逻辑:当我们使用@0bserved装饰过的数据,属性改变时,
// 就会监听到遍历依赖它的 @0bjectLink 包装类,通知数据更新。
Text('这个值不会更新:'+ this.PersonArray[0].age)
ForEach(this.PersonArray,(item:Person,index:number)=>{
ChildCom({
itemObj: item,
// 我们现在就可以更改第层的属性了,父组件进行更改
editorHandler:()=>{
item.age++
}
})
})
}
}
}
... 其他代码不变
点击第一个按钮后,文本框中的数据会变化嘛

有的小伙伴会说:会做更改,有的小伙伴可能会说:不会更改。
下面我们就是看到真相的时刻

文本框中的数据不会更改,为什么呢?
因为:当我们使用@0bserved装饰过的数据,属性改变时,
就会监听到遍历依赖它的 @0bjectLink 包装类,通知数据更新。
文本框中的 this.PersonArray[0].age 没有使用@0bjectLink包装。
因此不会进行界面的跟新
如果我们想要this.PersonArray[0].age更新的话,就需要使用@0bjectLink包装
更新文本框中的 this.PersonArray[0].age
我们把 this.PersonArray[0].age 的数据值单独抽离成为一个组件。
原因是:@ObjectLink修饰符不能用在 Entry 修饰的组件中使用
interface PersonList{
name:string
id:string
age:number
}
// 将数据用类的方式进行实例化,而不能用接口的方式进行。因为:@Observed修饰时必须是使用类进行初始
@Observed
class Person{
name:string
id:string
age:number
constructor(obj:PersonList) {
this.name = obj.name
this.id = obj.id
this.age = obj.age
}
}
@Component
struct ChildCom {
// 在子组件的中使用@ObjectLink
@ObjectLink itemObj:Person
// 等会父组件会重写这个方法
editorHandler = ()=>{}
build() {
Column(){
Row(){
Text('姓名1:'+ this.itemObj.name).margin({right:20})
Text('年龄:'+ this.itemObj.age).margin({right:20})
Button('修改').onClick(()=>{
this.editorHandler()
})
}.height(70).backgroundColor('#cac').width('100%').margin({bottom:10}).padding({left:10, right:10})
}
}
}
@Component
struct SonText {
@ObjectLink infoAge:Person
build() {
Text('这个值不会更新:'+ this.infoAge.age)
}
}
@Entry
@Component
struct Index {
@State PersonArray:PersonList[]=[
new Person({
name:'张三',
id:'user01',
age:19
}),
new Person({
name:'李四',
id:'user02',
age:22
})
]
build() {
Column() {
// 属性更新的逻辑:当我们使用@0bserved装饰过的数据,属性改变时,
// 就会监听到遍历依赖它的 @0bjectLink 包装类,通知数据更新。
// 但是下面的 this.PersonArray[0].ag 没有使用@0bjectLink进行包装,所以不会更新
// Text('这个值不会更新:'+ this.PersonArray[0].age)
// 我们把它变成组件,在组件中就可以使用 @0bjectLink
SonText({
infoAge: this.PersonArray[0]
})
ForEach(this.PersonArray,(item:Person,index:number)=>{
ChildCom({
itemObj: item,
// 我们现在就可以更改第层的属性了,父组件进行更改
editorHandler:()=>{
item.age++
}
})
})
}
}
}

装饰器更改第二层的数据会造成整项重新跟新(图片闪烁一下)
前面我们说了:
装饰器仅能观察到第一层的变化。对于多层嵌套的情况,比如对象数组等。
第2层属性的变化是无法观察到的。
因此我们会是下面的办法
let newItemObj:PersonList = this.PersonArray[index]
newItemObj.age+=1
// Array.splice(从第几项开始删除,删除几个,替换的项1,替换的项2,...)
this.PersonArray.splice(index,1,newItemObj)
但是这样更新年龄的时候,头像会闪动一下。因为跟新了整项。
使用Observed&、ObjectLink装饰的话就可以做到精确跟新。不会闪烁。
@Prop更新整项造成图像闪烁问题
interface PersonList{
name:string
id:string
age:number,
imgUrl:string
}
class Person{
name:string
id:string
age:number
imgUrl:string
constructor(obj:PersonList) {
this.name = obj.name
this.id = obj.id
this.age = obj.age
this.imgUrl = obj.imgUrl
}
}
@Component
struct ChildCom {
// 在子组件的中使用@ObjectLink
@Prop itemObj:Person
// 等会父组件会重写这个方法
editorHandler = ()=>{}
build() {
Column(){
Row(){
Image(this.itemObj.imgUrl).width(50).borderRadius(25).margin({right:20})
Text('姓名:'+ this.itemObj.name).margin({right:20})
Text('年龄:'+ this.itemObj.age).margin({right:20})
Button('修改').onClick(()=>{
this.editorHandler()
})
}.height(70).backgroundColor('#cac').width('100%').margin({bottom:10}).padding({left:10, right:10})
}
}
}
@Entry
@Component
struct Index {
@State PersonArray:PersonList[]=[
new Person({
name:'张三',
id:'user01',
age:19,
imgUrl:'https://p3-passport.byteacctimg.com/img/mosaic-legacy/3795/3047680722~130x130.awebp'
}),
new Person({
name:'李四',
id:'user02',
age:22,
imgUrl:'https://p9-passport.byteacctimg.com/img/user-avatar/98fd632fb172e17c564e253895d192bf~130x130.awebp'
})
]
build() {
Column() {
ForEach(this.PersonArray,(item:Person,index:number)=>{
ChildCom({
itemObj: item,
// 我们现在就可以更改第层的属性了,父组件进行更改
editorHandler:() => {
// this.PersonArray[index]的类型不是Person类型,是PersonList类型。
// 从这里我们可以看出来。==> @State PersonArray:PersonList[]=[{},{}]
let newItemObj:PersonList = this.PersonArray[index]
newItemObj.age+=1
// Array.splice(从第几项开始删除,删除几个,替换的项1,替换的项2,...)
this.PersonArray.splice(index,1,newItemObj)
}
})
})
}
}
}

最后的总结
@Link可以实现数据的双向绑定。
@Provide、Consume跨层传递。中间层对数据不需要做任何的处理。
@Observed&、ObjectLink更改多层结构的数据,同时会跟新界面,不会造成图像闪烁。
@Prop更新第二层的数据会造成整项跟新,图像闪烁问题。
@Link双向绑定和@Provide、Consume跨层传递、@Observed&@ObjectLink更改多层结构的数据的更多相关文章
- Vue数据双向绑定不起作用、Vue如何正确的手动添加json数据、Vue视图层不刷新、手动刷新视图层
Vue.set(obj,"key","value") 如果接收到来自服务器的消息时,我们需要对其进性进一步处理 我们想当然的会直接将数据添加进json 像这样: ...
- 数据的双向绑定 Angular JS
接触AngularJS许了,时常问自己一些问题,如果是我实现它,会在哪些方面选择跟它相同的道路,哪些方面不同.为此,记录了一些思考,给自己回顾,也供他人参考. 初步大致有以下几个方面: 数据双向绑定 ...
- 我的angularjs源码学习之旅3——脏检测与数据双向绑定
前言 为了后面描述方便,我们将保存模块的对象modules叫做模块缓存.我们跟踪的例子如下 <div ng-app="myApp" ng-controller='myCtrl ...
- vue双向绑定的原理及实现双向绑定MVVM源码分析
vue双向绑定的原理及实现双向绑定MVVM源码分析 双向数据绑定的原理是:可以将对象的属性绑定到UI,具体的说,我们有一个对象,该对象有一个name属性,当我们给这个对象name属性赋新值的时候,新值 ...
- 深入理解Proxy 及 使用Proxy实现vue数据双向绑定
阅读目录 1.什么是Proxy?它的作用是? 2.get(target, propKey, receiver) 3.set(target, propKey, value, receiver) 4.ha ...
- 数据的双向绑定 Angular JS之开端篇
接触AngularJS许了,时常问自己一些问题,如果是我实现它,会在哪些方面选择跟它相同的道路,哪些方面不同.为此,记录了一些思考,给自己回顾,也供他人参考. 初步大致有以下几个方面: 数据双向绑定 ...
- React中的“双向绑定”
概述 React并不是一个MVVM框架,其实它连一个框架都算不上,它只是一个库,但是react生态系统中的flux却是一个MVVM框架,所以我研究了一下flux官方实现中的"双向绑定&quo ...
- ionic3.x angular4.x ng4.x 自定义组件component双向绑定之自定义计数器
本文主要示例在ionic3.x环境下实现一个自定义计数器,实现后最终效果如图: 1.使用命令创建一个component ionic g component CounterInput 类似的命令还有: ...
- 用原生 JS 实现双向绑定及应用实例
写在前面: 所谓的双向绑定,无非是从界面的操作能实时反映到数据,数据的变更也能实时展现到界面.angular封装了双向绑定的方法,使双向绑定变得十分简单.但是在有些场景下(比如下面那个场景),不能使用 ...
- 深入学习AngularJS中数据的双向绑定机制
来自:http://www.jb51.net/article/80454.htm Angular JS (Angular.JS) 是一组用来开发Web页面的框架.模板以及数据绑定和丰富UI组件.它支持 ...
随机推荐
- 什么是RESTful 或 GraphQL?
RESTful 与 GraphQL 深度解析 在前端的开发过程中,相信 everyone 对 Get.POST 等请求方式都很熟悉,那么这些请求是归于哪种架构或者设计风格可能又不是很熟.现在在这简单的 ...
- 【Linux】U-Boot 加载并启动 Linux 系统程序
U-Boot 加载并启动 Linux 系统程序 零.介绍 最近在玩一些嵌入式的开发板,在引导操作系统时需要用到U-Boot,故此研究一下. U-Boot(Universal Bootloader)是一 ...
- leetcode每日一题:对角线上的质数
题目 2614. 对角线上的质数 给你一个下标从 0 开始的二维整数数组 nums . 返回位于 nums 至少一条 对角线 上的最大 质数 .如果任一对角线上均不存在质数,返回 0 . 注意: 如果 ...
- JBoltAI Function Call技术解析:如何实现AI模型与企业系统的无缝对话
JBoltAI Function Call技术解析: 如何实现AI模型与企业系统的无缝对话 在企业级AI应用开发中,如何让大模型能力与现有系统高效协同一直是技术难点.JBoltAI框架通过Functi ...
- 初学嵌入式是弄linux还是单片机?
作为一个从机械转行到嵌入式的工程师,我深刻理解初学者面临的困惑.嵌入式领域分支众多,初期选择Linux还是单片机确实是个让人纠结的问题.我当年就在这个问题上纠结了好久,走了不少弯路. 其实,我之所以能 ...
- zookeeper选主机制
Zookeeper选主机制 一.Server工作状态 每个Server在工作过程中有四种状态: LOOKING:竞选状态,当前Server不知道leader是谁,正在搜寻. LEADING:领导者状态 ...
- 剑气纵横千行码:AI写就的设计模式侠客行助您仗剑走天涯
烟火里的江湖旧忆 暮色里,代码侠的电动车在巷口急刹,外卖箱里的热汤晃出细响,恍惚间竟像当年工厂堡锻造炉的轰鸣.难得休息之余,他抹了把额头的汗,扶了扶常开网约车的腰,摸了摸自己晒黑的脸,偶感那颠炒粉的手 ...
- Java 的 CMS 垃圾回收流程
Java 的 CMS 垃圾回收流程 CMS(Concurrent Mark-Sweep)垃圾回收器 是一种并发垃圾回收器,旨在减少垃圾回收时的停顿时间,适用于对低延迟要求较高的应用.CMS 主要通过并 ...
- ubuntu nginx + php7.2 + mysql5.7环境搭建
一.换源 备份原来的源 sudo cp /etc/apt/sources.list /etc/apt/sources_init.list 更换源 sudo gedit /etc/apt/sources ...
- linux 指定运行级别
目录 基本介绍 指定运行级别 基本介绍 0:关机 1:单用户 2:多用户状态没有网络服务 3:多用户状态有网络服务 4:系统未使用保留给用户 5:图形界面 6:系统重启 常用的运行级别是3和5,也可以 ...