HarmonyOS 鸿蒙Next中页面间的数据共享

HarmonyOS 鸿蒙Next中页面间的数据共享 问题是:在A中点击按钮切换B、C页面时,在这两个切换的页面中,有一个共用组件D,组件D里面有个值,想要实现,D组件这个值,在B、C页面切换的过程中,能保持同步,有什么好的办法实现吗?

我试过,给切换按钮的布尔值加一个watch,每次改变,就让num重新赋值,但是不中!

代码如下:

这是主页面A:

import { HMRouter } from "@hadss/hmrouter"
import { ComB } from "./ComB"
import { ComC } from "./ComC"

@HMRouter({ pageUrl: 'ComA' })
@Component
export struct ComA {
  @State isChange: boolean = false

  build() {
    Column() {
      Button('切换按钮').onClick(() => {
        this.isChange = !this.isChange
      })

      if (this.isChange) {
        ComB()
      } else {
        ComC()
      }
    }
  }
}

子页面B:

import { ComD } from "./ComD"

@Component
export struct ComB {
  build() {
    Column() {
      Text('页面B')
      ComD()
    }.width('100%').height(200).backgroundColor('#857')
  }
}

子页面C

import { ComD } from "./ComD"

@Component
export struct ComC {

  build() {
    Column() {
      Text('页面C')

      ComD()
    }.width('100%').height(100).backgroundColor('#c0c0c0')
  }
}

子页面B和子页面C的公共组件D

其中加了一个页面展示的监听,每次这个D组件展示的时候,就重新给num赋值为1

问题就是,在切换B、C页面时,这个num就会等于0,并不会维持之前的值,因为刚进入页面的时候,num被赋值为1,在切换之后,num就等于0了。

有一个解决的办法,但是我觉得不完美,其实这个赋值的位置是一个方法,这个方法会返回一个number,再重新赋值,现在的解决办法,就是定义这个num的时候,默认值不给0,直接写这个方法名字,就可以实现公共组件D中的num值保持同步。

import { HMLifecycleState, HMPopInfo, HMRouter, HMRouterMgr } from "@hadss/hmrouter"

@Component
export struct ComD {
  @State num: number = 0

  aboutToAppear(): void {
    HMRouterMgr.getCurrentLifecycleOwner()?.addObserver(HMLifecycleState.onShown, (ctx) => {
      this.num = 1
    })
  }

  build() {
    Column() {
      Text(`页面D${this.num}`)
    }
  }
}

更多关于HarmonyOS 鸿蒙Next中页面间的数据共享的实战教程也可以访问 https://www.itying.com/category-93-b0.html

9 回复

可以再试下以下两种方式:

方式一:通过[@Link装饰器](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-link#概述)实现父子组件双向同步

@HMRouter({ pageUrl: 'ComA' })
@Component
export struct ComA {
  @State isChange: boolean = false
  @State num: number = 0

  build() {
    Column() {
      Button('切换按钮').onClick(() => {
        this.isChange = !this.isChange
      })
      if (this.isChange) {
        ComB({
          num: $num
        })
      } else {
        ComC({
          num: $num
        })
      }
    }
  }
}

@Component
export struct ComB {
  [@Link](/user/Link) num:number;

  build() {
    Column() {
      Text('页面B')
      ComD({
        num:$num
      })
    }
    .width('100%')
    .height(200)
    .backgroundColor('#857')
  }
}

@Component
export struct ComD {
  [@Link](/user/Link) num: number;

  build() {
    Column() {
      Text(`页面D${this.num}`)
        .onClick(() => {
          let tmp:number = this.num + 1;
          this.num = tmp
        })
    }
  }
}

方式二:单例类实现数据共享

@ObservedV2
export class GetNum{
  private static instance:GetNum;
  @Trace
  private num:number = 0;
  private constructor() {
  }
  public static getInstance(){
    if (!GetNum.instance) {
      GetNum.instance = new GetNum();
    }
    return GetNum.instance
  }
  public getNum():number{
    return this.num;
  }
  public setNum(num: number) {
    this.num = num;
  }
}


@Component
export struct ComD {
  num: GetNum = GetNum.getInstance()

  build() {
    Column() {
      Text(`页面D${this.num.getNum()}`)
        .onClick(() => {
          let tmp: number = this.num.getNum() + 1;
          this.num.setNum(tmp)
        })
    }
  }
}

更多关于HarmonyOS 鸿蒙Next中页面间的数据共享的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


感谢感谢!明白了!通透!!!一下想通了!,

可以通过AppStorage实现页面间的数据同步,

对于不同页面之间的参数传递,可以使用AppStorage实现。AppStorage是应用全局的UI状态存储,与应用的进程绑定,由UI框架在应用程序启动时创建。使用SubscribedAbstractProperty可以读取、设置从AppStorage/LocalStorage同步属性的数据。

如:

@Component
export struct ComD {
  @State num: SubscribedAbstractProperty<number> = AppStorage.link('ComDNum');

  build() {
    Column() {
      Text(`页面D${this.num.get()}`)
        .onClick(() => {
          let num: number = this.num.get() + 1
          this.num.set(num)
        })
    }
  }
}

谢谢,这也是个办法~想看看有没有更好的解决办法~,

更好的方式?你是想要什么样的实现?

1.可以通过AppStorage实现数据同步

2.为共用组件D创建一个静态的控制器,全局唯一来实现控制,对组件的操作都通过控制器来操作,数据传递也通过控制器来处理

MVVM模式-状态管理(V1)-学习UI范式状态管理-UI开发 (ArkTS声明式开发范式)-ArkUI(方舟UI框架)-应用框架 - 华为HarmonyOS开发者

可以的可以的!!!感谢~,

在HarmonyOS Next中,页面间数据共享主要通过UIAbility的AppStorage、LocalStorage和PersistentStorage实现。AppStorage提供全局内存数据共享,LocalStorage用于页面级数据共享,PersistentStorage支持持久化存储。此外,使用EventHub进行基于订阅发布机制的事件通信,也可实现跨页面数据传递。

在HarmonyOS Next中,要实现B、C页面间共用组件D的数据同步,你当前的方法确实存在问题。组件D在每次页面切换时都会重新创建,导致状态重置。以下是几种更合适的解决方案:

1. 使用AppStorage(推荐)

这是跨组件/页面共享数据的最佳方式:

// 在公共模块或组件初始化时设置初始值
AppStorage.SetOrCreate<number>('sharedNum', 0);

// 组件D中使用
@Component
export struct ComD {
  @StorageLink('sharedNum') num: number = 0;

  build() {
    Column() {
      Text(`页面D${this.num}`)
      Button('增加').onClick(() => {
        this.num += 1; // 修改会自动同步到所有使用该StorageLink的地方
      })
    }
  }
}

2. 使用LocalStorage

如果共享范围仅限于特定页面树:

// 在页面A中创建并传递LocalStorage
@HMRouter({ pageUrl: 'ComA' })
@Component
export struct ComA {
  @State isChange: boolean = false
  storage: LocalStorage = new LocalStorage();

  aboutToAppear() {
    this.storage.setOrCreate('sharedNum', 0);
  }

  build() {
    Column() {
      Button('切换按钮').onClick(() => {
        this.isChange = !this.isChange;
      })

      if (this.isChange) {
        ComB({ storage: this.storage })
      } else {
        ComC({ storage: this.storage })
      }
    }
  }
}

// 组件D中使用
@Component
export struct ComD {
  @LocalStorageLink('sharedNum') num: number = 0;

  build() {
    Column() {
      Text(`页面D${this.num}`)
    }
  }
}

3. 使用单例模式管理状态

创建全局状态管理器:

// SharedStateManager.ts
export class SharedStateManager {
  private static instance: SharedStateManager;
  private _num: number = 0;
  
  private constructor() {}
  
  static getInstance(): SharedStateManager {
    if (!SharedStateManager.instance) {
      SharedStateManager.instance = new SharedStateManager();
    }
    return SharedStateManager.instance;
  }
  
  get num(): number {
    return this._num;
  }
  
  set num(value: number) {
    this._num = value;
  }
}

// 组件D中使用
@Component
export struct ComD {
  private sharedState = SharedStateManager.getInstance();
  @State num: number = this.sharedState.num;

  build() {
    Column() {
      Text(`页面D${this.num}`)
      Button('修改').onClick(() => {
        this.sharedState.num = 5;
        this.num = this.sharedState.num;
      })
    }
  }
}

问题分析

你当前代码的问题在于:

  1. 每次切换B/C页面时,组件D都会重新实例化
  2. aboutToAppear中的监听器在每次组件创建时都会设置num=1,但切换时组件销毁重建,状态丢失
  3. 使用@State装饰的状态是组件实例私有的

推荐使用AppStorage方案,它专为跨组件状态共享设计,无需复杂的生命周期管理,数据修改会自动同步到所有相关组件。

回到顶部