@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更改多层结构的数据的更多相关文章

  1. Vue数据双向绑定不起作用、Vue如何正确的手动添加json数据、Vue视图层不刷新、手动刷新视图层

    Vue.set(obj,"key","value") 如果接收到来自服务器的消息时,我们需要对其进性进一步处理 我们想当然的会直接将数据添加进json 像这样: ...

  2. 数据的双向绑定 Angular JS

    接触AngularJS许了,时常问自己一些问题,如果是我实现它,会在哪些方面选择跟它相同的道路,哪些方面不同.为此,记录了一些思考,给自己回顾,也供他人参考. 初步大致有以下几个方面: 数据双向绑定 ...

  3. 我的angularjs源码学习之旅3——脏检测与数据双向绑定

    前言 为了后面描述方便,我们将保存模块的对象modules叫做模块缓存.我们跟踪的例子如下 <div ng-app="myApp" ng-controller='myCtrl ...

  4. vue双向绑定的原理及实现双向绑定MVVM源码分析

    vue双向绑定的原理及实现双向绑定MVVM源码分析 双向数据绑定的原理是:可以将对象的属性绑定到UI,具体的说,我们有一个对象,该对象有一个name属性,当我们给这个对象name属性赋新值的时候,新值 ...

  5. 深入理解Proxy 及 使用Proxy实现vue数据双向绑定

    阅读目录 1.什么是Proxy?它的作用是? 2.get(target, propKey, receiver) 3.set(target, propKey, value, receiver) 4.ha ...

  6. 数据的双向绑定 Angular JS之开端篇

    接触AngularJS许了,时常问自己一些问题,如果是我实现它,会在哪些方面选择跟它相同的道路,哪些方面不同.为此,记录了一些思考,给自己回顾,也供他人参考. 初步大致有以下几个方面: 数据双向绑定 ...

  7. React中的“双向绑定”

    概述 React并不是一个MVVM框架,其实它连一个框架都算不上,它只是一个库,但是react生态系统中的flux却是一个MVVM框架,所以我研究了一下flux官方实现中的"双向绑定&quo ...

  8. ionic3.x angular4.x ng4.x 自定义组件component双向绑定之自定义计数器

    本文主要示例在ionic3.x环境下实现一个自定义计数器,实现后最终效果如图: 1.使用命令创建一个component ionic g component CounterInput 类似的命令还有: ...

  9. 用原生 JS 实现双向绑定及应用实例

    写在前面: 所谓的双向绑定,无非是从界面的操作能实时反映到数据,数据的变更也能实时展现到界面.angular封装了双向绑定的方法,使双向绑定变得十分简单.但是在有些场景下(比如下面那个场景),不能使用 ...

  10. 深入学习AngularJS中数据的双向绑定机制

    来自:http://www.jb51.net/article/80454.htm Angular JS (Angular.JS) 是一组用来开发Web页面的框架.模板以及数据绑定和丰富UI组件.它支持 ...

随机推荐

  1. 什么是RESTful 或 GraphQL?

    RESTful 与 GraphQL 深度解析 在前端的开发过程中,相信 everyone 对 Get.POST 等请求方式都很熟悉,那么这些请求是归于哪种架构或者设计风格可能又不是很熟.现在在这简单的 ...

  2. 【Linux】U-Boot 加载并启动 Linux 系统程序

    U-Boot 加载并启动 Linux 系统程序 零.介绍 最近在玩一些嵌入式的开发板,在引导操作系统时需要用到U-Boot,故此研究一下. U-Boot(Universal Bootloader)是一 ...

  3. leetcode每日一题:对角线上的质数

    题目 2614. 对角线上的质数 给你一个下标从 0 开始的二维整数数组 nums . 返回位于 nums 至少一条 对角线 上的最大 质数 .如果任一对角线上均不存在质数,返回 0 . 注意: 如果 ...

  4. JBoltAI Function Call技术解析:如何实现AI模型与企业系统的无缝对话

    JBoltAI Function Call技术解析: 如何实现AI模型与企业系统的无缝对话 在企业级AI应用开发中,如何让大模型能力与现有系统高效协同一直是技术难点.JBoltAI框架通过Functi ...

  5. 初学嵌入式是弄linux还是单片机?

    作为一个从机械转行到嵌入式的工程师,我深刻理解初学者面临的困惑.嵌入式领域分支众多,初期选择Linux还是单片机确实是个让人纠结的问题.我当年就在这个问题上纠结了好久,走了不少弯路. 其实,我之所以能 ...

  6. zookeeper选主机制

    Zookeeper选主机制 一.Server工作状态 每个Server在工作过程中有四种状态: LOOKING:竞选状态,当前Server不知道leader是谁,正在搜寻. LEADING:领导者状态 ...

  7. 剑气纵横千行码:AI写就的设计模式侠客行助您仗剑走天涯

    烟火里的江湖旧忆 暮色里,代码侠的电动车在巷口急刹,外卖箱里的热汤晃出细响,恍惚间竟像当年工厂堡锻造炉的轰鸣.难得休息之余,他抹了把额头的汗,扶了扶常开网约车的腰,摸了摸自己晒黑的脸,偶感那颠炒粉的手 ...

  8. Java 的 CMS 垃圾回收流程

    Java 的 CMS 垃圾回收流程 CMS(Concurrent Mark-Sweep)垃圾回收器 是一种并发垃圾回收器,旨在减少垃圾回收时的停顿时间,适用于对低延迟要求较高的应用.CMS 主要通过并 ...

  9. ubuntu nginx + php7.2 + mysql5.7环境搭建

    一.换源 备份原来的源 sudo cp /etc/apt/sources.list /etc/apt/sources_init.list 更换源 sudo gedit /etc/apt/sources ...

  10. linux 指定运行级别

    目录 基本介绍 指定运行级别 基本介绍 0:关机 1:单用户 2:多用户状态没有网络服务 3:多用户状态有网络服务 4:系统未使用保留给用户 5:图形界面 6:系统重启 常用的运行级别是3和5,也可以 ...