HarmonyOS鸿蒙Next中arkts页面A路由跳转页面B,传递map对象,B页面修改map,页面A的map同时变化

HarmonyOS鸿蒙Next中arkts页面A路由跳转页面B,传递map对象,B页面修改map,页面A的map同时变化

navPathStack.pushDestination 页面跳转,当页面从 A 跳转到 B 时,传递参数是 map<string, object> 时,时传递地址么?

现在发现 B 页面接收 map 参数后,添加或删除 key 处理完成,A 页面的 map 也会变化。

A 页面 :

@State mMapi:string, string> = new Map()
navPathStack.pushDestination({
  name: 'DuuMessageDetailPage',
  param: {
    mMapi:this.mMapi
  } 
})

B 页面

@Builder
export function DetailPageBuilder(name: string,param: InfoParam) {
  DetailPage({
    mMapi:param.mMapi,
  });
}
@State mMapi:Map<string, string> = new Map()
aboutToAppear(): void {
  this.mMapi.delete("1")
}

请问这个传递的 map 是浅拷贝么?怎么解决这种问题?


更多关于HarmonyOS鸿蒙Next中arkts页面A路由跳转页面B,传递map对象,B页面修改map,页面A的map同时变化的实战教程也可以访问 https://www.itying.com/category-93-b0.html

10 回复

在ArkTS中,当页面A通过路由跳转到页面B并传递map对象时,如果B页面修改map,页面A的map也会同时变化,这是因为对象传递的是引用。以下是详细的解决方案:

1:深拷贝传递

// 页面A
@Component
struct PageA {
  @State originalMap: Map<string, any> = new Map([
    ['name', '张三'],
    ['age', 25],
    ['city', '北京']
  ])

  build() {
    Column() {
      Text('页面A')
        .fontSize(20)
      
      Text(`原始数据: ${JSON.stringify(Array.from(this.originalMap))}`)
        .fontSize(14)
        .margin(10)
      
      Button('跳转到页面B')
        .onClick(() => {
          // 深拷贝map对象
          const copiedMap = this.deepCopyMap(this.originalMap)
          router.pushUrl({
            url: 'pages/PageB',
            params: {
              dataMap: copiedMap
            }
          })
        })
    }
  }

  // 深拷贝Map对象
  private deepCopyMap(map: Map<string, any>): Map<string, any> {
    const newMap = new Map()
    for (const [key, value] of map) {
      if (typeof value === 'object' && value !== null) {
        newMap.set(key, JSON.parse(JSON.stringify(value)))
      } else {
        newMap.set(key, value)
      }
    }
    return newMap
  }
}

2:使用状态管理

// 全局状态管理
class GlobalState {
  private static instance: GlobalState
  @State mapData: Map<string, any> = new Map()

  static getInstance(): GlobalState {
    if (!GlobalState.instance) {
      GlobalState.instance = new GlobalState()
    }
    return GlobalState.instance
  }

  setMapData(map: Map<string, any>) {
    this.mapData = new Map(map)
  }

  getMapData(): Map<string, any> {
    return new Map(this.mapData)
  }
}

// 页面A
@Component
struct PageA {
  @State originalMap: Map<string, any> = new Map([
    ['name', '张三'],
    ['age', 25],
    ['city', '北京']
  ])

  build() {
    Column() {
      Text('页面A')
        .fontSize(20)
      
      Text(`原始数据: ${JSON.stringify(Array.from(this.originalMap))}`)
        .fontSize(14)
        .margin(10)
      
      Button('跳转到页面B')
        .onClick(() => {
          // 存储到全局状态
          GlobalState.getInstance().setMapData(this.originalMap)
          router.pushUrl({
            url: 'pages/PageB'
          })
        })
    }
  }
}

// 页面B
@Component
struct PageB {
  @State receivedMap: Map<string, any> = new Map()

  aboutToAppear() {
    // 从全局状态获取数据
    this.receivedMap = GlobalState.getInstance().getMapData()
  }

  build() {
    Column() {
      Text('页面B')
        .fontSize(20)
      
      Text(`接收数据: ${JSON.stringify(Array.from(this.receivedMap))}`)
        .fontSize(14)
        .margin(10)
      
      Button('修改数据')
        .onClick(() => {
          this.receivedMap.set('age', 30)
          this.receivedMap.set('city', '上海')
        })
      
      Button('返回页面A')
        .onClick(() => {
          router.back()
        })
    }
  }
}

更多关于HarmonyOS鸿蒙Next中arkts页面A路由跳转页面B,传递map对象,B页面修改map,页面A的map同时变化的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


Navigation的NavPathStack.pushDestination方法传递对象参数时,默认采用浅拷贝方式。对于Map这类堆内存存储的复杂对象,实际传递的是对象引用而非独立副本。当B页面通过this.mMap.delete(“1”)修改Map时,本质上操作的是A页面原始Map对象的内存地址,导致多页面状态意外联动。楼主试试深拷贝传递

// A页面传递前深拷贝

const clonedMap = new Map<string, string>(this.mMap);

navPathStack.pushDestination({

  name: 'DuuMessageDetailPage',

  param: { mMap: clonedMap }

});

// B页面接收后初始化新Map

@State mMMap: Map<string, string> = new Map();

aboutToAppear() {

  this.mMap = new Map(param.mMap); // 通过构造函数创建独立实例

  this.mMap.delete("1"); // 仅影响B页面实例
}

第一种方法:

可以结合appStorage一起使用

  1. 使用 @StorageLink + AppStorage 实现跨页面双向同步(或 @Provide/@Consume 实现组件树内同步)。
  2. 通过 Navigator 组件的 params 传递 Map 的引用标识(非直接传递 Map)。
  3. Map 需使用 API 11+ 支持的类型,并用 @Observed 装饰类(若涉及嵌套结构)

第二种方法

也可以使用V2装饰器,使用官方的全局状态管理基于StateStore的全局状态管理-声明式语法 - 华为HarmonyOS开发者

第三种 使用Emitter进行线程间通信

后面的页面emit事件,前面的页面监听页面

使用Emitter进行线程间通信-进程线程通信-Basic Services Kit(基础服务)-基础功能-系统 - 华为HarmonyOS开发者

我看楼主没有重新接收参数的方法,比如HMRouter是这样接收的

let res = HMRouterMgr.getCurrentParam() as NewWindowPageParam

楼主使用传递的方法是用组件的状态变量传递值,这样的值会被改变,页面传递参数是通过方法类来重新获取,重新赋值,不会存在楼主说的情况

可以使用如下方法去定义相关参数,可以实现多页面同步数据

@ObservedV2 
@Trace

如:

@ObservedV2
export class Page1Param {
@Trace static param: string = '';
}

不要这样在组件创建的时候传参,也就是不要这样写:

@Builder
export function DetailPageBuilder(name: string,param: InfoParam) {
  DetailPage({
    
    mMap:param.mMap,
 

  });
}

你可以在DetailPage页面使用 NavDestination的onReady方法接收参数,例如:

NavDestination.onReady(ctx=>{ctx.pathInfo.param})

获取传参

谁知道啊?传递路由参数的时候时复杂对象,怎么办?

标题

这是第一段内容。

这是第二段内容。

在HarmonyOS鸿蒙Next中,使用ArkTS进行页面路由跳转时,传递的Map对象是按引用传递的。当页面B修改接收到的Map对象时,由于页面A和页面B持有的是同一个Map对象的引用,页面A中的Map内容会同步变化。这种设计符合ArkTS基于TypeScript的引用类型特性,不需要特别处理对象共享问题。

在HarmonyOS Next的ArkTS中,Map对象作为参数传递时确实是引用传递(浅拷贝),因此B页面修改Map会影响A页面的原始数据。这是JavaScript/TypeScript的标准行为。

解决方案:

  1. 使用深拷贝传递Map:
// A页面跳转时
navPathStack.pushDestination({
  name: 'DuuMessageDetailPage',
  param: {
    mMap: new Map(this.mMap) // 创建新Map实例
  }
})
  1. 或者在B页面接收时创建副本:
// B页面
@State mMap: Map<string, string> = new Map(param.mMap) // 初始化时创建副本
  1. 对于复杂对象建议使用JSON序列化:
// A页面
navPathStack.pushDestination({
  name: 'DuuMessageDetailPage',
  param: {
    mMap: JSON.parse(JSON.stringify(Array.from(this.mMap)))
  }
})

// B页面
const mapData = new Map(JSON.parse(param.mMap))

选择哪种方式取决于你的具体使用场景和性能要求。第一种方式最简单直接。

回到顶部