@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组件.它支持 ...
随机推荐
- 选择排序--java进阶day06
1.选择排序 https://kdocs.cn/l/ciMkwngvaWfz?linkname=150996881 了解了选择排序之后,我们来找其中的规律 2.规律 选择排序就是一个元素和数组后续元素 ...
- Quartz.NET - 教程 12: Quartz 的其他特性
译者注: 目录在这 Quartz.NET 3.x 教程 原文在这 Lesson 12: Miscellaneous Features of Quartz 插件 Quartz 提供了一个用于插入附加功能 ...
- 学习FASTAPI
弯弯曲曲的学习之路 学了那么多语言,都是半途而废.包括java,Javascript,go,php,ruby等等乱七八糟. 除了c的自由和pascal的优美,FoxPro简单,其他都似懂非懂入不了法眼 ...
- 学习EXTJS6(9)面向对象的基础框架-1
Ext创造一套精细的对象模型与API,用这套API,可以快速实现对象的定义.创建.继承和扩展:1. 1.创建新类 Ext.define('demo.Demo',{ name: 'usegear', h ...
- 《数组》--DAY2--快慢指针法
1.什么是双指针? 双指针,指的是在遍历对象的过程中,不是普通的使用单个指针进行访问,而是使用两个相同方向(快慢指针)或者相反方向(对撞指针)的指针进行扫描,从而达到相应的目的. 2.快慢指针 2.1 ...
- SpringMvc怎么样把数据带给页面
例子. /** * SpringMVC除过在方法上传入原生的request和session外还能怎么样把数据带给页面 * * 1).可以在方法处传入Map.或者Model或者ModelMap. * 给 ...
- 如何使用Nacos作为配置中心统一管理配置
如何使用Nacos作为配置中心统一管理配置 1).引入依赖, <dependency> <groupId>com.alibaba.cloud</groupId> & ...
- 基于Vosk与Transformers的会议摘要生成系统实战教程
一.项目背景与价值 在现代办公场景中,会议记录与摘要生成是提升工作效率的重要环节.传统人工记录方式存在效率低.易遗漏等问题,而基于AI的解决方案可以实时转录会议内容并生成结构化摘要.本教程将指导开发者 ...
- Excel导入操作,poi
导入操作,仅供参考,具体情况具体而论 @Override public ReturnObject inforImport(LogySbjsJdsbqxxxParts entity, HttpServl ...
- nndeploy开源推理框架教程来袭,模型推理全流程,轻松上手,一键精通!
大家好,我们是 nndeploy 开源团队.我们专注于打造一款端到端的模型推理和部署框架 -- nndeploy,旨在为用户提供高效.便捷.灵活且兼容主流框架的模型推理和部署体验. 此次,我们开发了 ...