HarmonyOS鸿蒙Next中请教跳到主界面对应tab怎么实现

HarmonyOS鸿蒙Next中请教跳到主界面对应tab怎么实现 假如我现在某个子界面需要登录,我点登录就跳转到主界面Main对应的我的tab界面,应该怎么实现。例如像安卓可以设置界面singleTask模式可以回主界面。鸿蒙怎么实现

如下是我的主界面,我在某个子界面点击登录,然后杀死子界面 回到Index对应的我的界面。用什么比较好实现?页面跳转大多是用Nav跳转的

@Entry
@Component
struct Index {

  @Provide('pageIndex') pageIndex: NavPathStack = new NavPathStack()

  collectController: CollectController = new CollectController()

  @State currentIndex: number = 0;

  @State menus: MenuItemType[] = [
    { icon: 'svg_home', text: '首页'},
    { icon: 'svg_find', text: '教程' },
    { icon: 'svg_collect', text: '收藏' },
    { icon: 'svg_me', text: '我的' },
  ]

  @Builder
  tabBuilderBar(item: MenuItemType, index: number) {
    Column({ space: 4 }) {
      Image($r(`app.media.${item.icon}`))
        .width(25)
        .fillColor(index === this.currentIndex ? $r('app.color.color_load') : '#808182')
      Text(item.text)
        .fontSize(12)
        .fontColor(index === this.currentIndex ? $r('app.color.color_load') : '#808182')
    }
  }

  @Builder
  tabBuilderContent(index: number) {
    if (index === 0) { //  首页界面
      HomeIndex()
    } else if (index === 1) { // 发现界面
     FindIndex()
    } else if (index === 2) { // 我的收藏
      CollectIndex({controller : this.collectController})
    }else if (index ===3) { // 个人信息界面
      MeIndex({controller : this.collectController})
    }
  }

  aboutToAppear(): void {
    HttpComWrapper.getInstance().getCityResult()
    if (UserUtils.loginNoNot()) { // 如果是登录状态,请求下用户的等级
      HttpComWrapper.getInstance().getUserLevel()
    }
  }

  build() {
    Navigation(this.pageIndex) {
      Column() {
        Tabs({ barPosition: BarPosition.End, index: this.currentIndex }) {
          ForEach(this.menus, (item: MenuItemType, index: number) => {
            TabContent() {
              this.tabBuilderContent(index)
            }
            .tabBar(this.tabBuilderBar(item, index))
          })
        }
        .scrollable(false) // 制滑动切换
        .animationDuration(0)
        .barBackgroundColor($r('app.color.main_bg'))
        .onChange((index: number) => {
          this.currentIndex = index
          if (index === 2) {
            this.collectController.onRefresh?.()
          }else if (index === 3) {
            this.collectController.onRefreshPay?.()
          }
        })
        .divider({
          strokeWidth: 1,
          color: '#ffeaeaea'
        })
       }
       .width('100%')
       .height('100%')
    }
    .hideToolBar(true)
    .width('100%')
    .height('100%')
  }
}

更多关于HarmonyOS鸿蒙Next中请教跳到主界面对应tab怎么实现的实战教程也可以访问 https://www.itying.com/category-93-b0.html

9 回复

Navigation导航采用push方法入栈后,页面实例会存储在路由栈内,即使采用push方法跳转到其它页面,之前的页面实例依旧在路由栈内,当采用pop/clear等删除路由栈页面实例的方法删除页面后,之前创建的页面实例就没办法再找回。若想要不刷新页面,跳转到之前已经创建过的页面,可以考虑采用以下方式代替pop方法:

可以采用LaunchMode中的单例模式(MOVE_TO_TOP_SINGLETON、POP_TO_SINGLETON)将路由栈内已有的页面实例替换到栈顶显示。实现方式参考:示例2

更多关于HarmonyOS鸿蒙Next中请教跳到主界面对应tab怎么实现的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


1.楼主可以参考一下这个项目LoginAndLogout: 本示例是基于Navigation实现导航跳转,采用PromptAction实现弹窗。模拟登录和注销的场景实现,且界面满足一多适配。

cke_575.png

2.基于Navigation组件实现导航跳转,采用PromptAction实现弹窗。模拟登录和注销的场景实现,且界面满足一多适配。应用登录符合隐私要求,实现正确的跳转逻辑,满足更好的用户体验。

3.这里面会涉及到如何拦截登录已经登录成功后的逻辑处理

清空路由,打开指定路由页面试试

背景知识:

首页我们需要知道 Tabs 的切换方式是在属性中绑定一个 index 参数。现在我们只要记录一下当前的index是什么,将值传入到登录页面,在登录页面获取完登录信息后直接将值传回来,通过 Tabs 中与index参数绑定的值,修改这个值就可以回到原位了。不过其中涉及到一个页面的销毁和重新加载,在跳转到登录页面是使用getRouter().pushUrl,在登录页面跳转回来首页是要清理之前的页面,使用getRouter().clear() + getRouter().replaceUrl 进行处理。

问题解决:

代码如下:

//1、 我的/个人页面操作判断是否要去登录
import { ToastUtil } from "@yunkss/eftool"
import { MyAccount } from "../LoginPage"

@Component
export struct Mine {
    @State message: string = "我的"

    aboutToAppear(): void {
        console.log("MyApp: Mine -> aboutToAppear")

        console.log("MyApp: Mine -> 获取到的用户信息:" + JSON.stringify(this.user))
    }

    build() {
        Column() {
            Button(this.message)
                .fontSize(20)
                .fontColor(Color.White)
                .fontWeight(FontWeight.Bold)

            Button("判断是否要登录")
                .fontSize(20)
                .fontColor(Color.White)
                .fontWeight(FontWeight.Bold)
                .onClick(() => {
                    //判断是否登录成功
                    let ac = AppStorage.get("myAccount") as MyAccount
                    if (ac) {
                        ToastUtil.showToast("登录成功")
                    } else {
                        this.getUIContext().getRouter().pushUrl({
                            url: "pages/LoginPage",
                            params: { index: 1 }
                        })
                    }
                })
        }
        .width("100%")
        .height("100%")
        .backgroundColor(Color.Yellow)
    }
}



//登录页面 2、
//封装的登录信息实体
export class MyAccount {
    nick: string = ""
    avatar: string = ""
    userId: string = ""
}

@Entry
@Component
struct LoginPage {
    @State message: string = '登录页面';
    index = 0

    aboutToAppear(): void {
        let p = this.getUIContext().getRouter().getParams() as Record<string, number>
        this.index = p["index"]
    }

    build() {
        Column({ space: 15 }) {
            Text(this.message)
                .width("100%")
                .height("150")
                .textAlign(TextAlign.Center)
                .fontSize(20)
                .fontColor(Color.Black)
                .fontWeight(FontWeight.Bold)
                .textAlign(TextAlign.Center)
            Button("登录")
                .fontSize(20)
                .fontColor(Color.White)
                .fontWeight(FontWeight.Bold)
                .onClick(() => {
                    //模拟登录获取的值
                    let ac = new MyAccount()
                    ac.nick = "测试昵称"
                    ac.avatar = "xx.png"
                    ac.userId = "123456"
                    AppStorage.setOrCreate("myAccount", ac)

                    //跳转到首页
                    this.getUIContext().getRouter().clear()
                    this.getUIContext().getRouter().replaceUrl({
                        url: "pages/TabsPage",
                        params: { index: this.index }
                    })
                })

        }
        .height('100%')
        .width('100%')
    }
}


// 3、tab主页面
import { AppStorageV2, Font } from '@kit.ArkUI';
import { HomePage } from './content/HomePage';
import { Mine } from './content/Mine';

@Entry
@Component
struct TabsPage {
    private tabsController: TabsController = new TabsController();
    @State currentIndex: number = 0;
    pathStack: NavPathStack =
        AppStorageV2.connect(NavPathStack, 'navStack', () => new NavPathStack())!

    aboutToAppear(): void {
        let p = this.getUIContext().getRouter().getParams() as Record<string, number>
        if (p) {
          //获取到参数登录页过来的参数切换
            this.currentIndex = p["index"]
        }

    }

    @Builder
    tabBarBuilder(title: string, targetIndex: number, selectedIcon: Resource,
        unselectIcon: Resource) {
        Column({ space: 5 }) {
            Image(this.currentIndex === targetIndex ? selectedIcon : unselectIcon)
                .width(24)
            Text(title)
                .fontSize(14)
                .fontColor(this.currentIndex === targetIndex ? '#0A59F7' : '#63AAAA')
                .textAlign(TextAlign.Center)
                .fontWeight(500)
        }
        .width('100%')
        .height('100%')
        .justifyContent(FlexAlign.Center)
        .alignItems(HorizontalAlign.Center)
    }

    build() {
        NavDestination() {
            Tabs({
                barPosition: BarPosition.End,
                controller: this.tabsController,
                //绑定一个 状态变量进行提切换 tab
                index: this.currentIndex
            }) {
                TabContent() {
                    HomePage()
                }
                .tabBar(this.tabBarBuilder('主页', 0, $r('app.media.ic_home_sel'),
                    $r('app.media.ic_home_normal')))

                TabContent() {
                    Mine()
                }
                .tabBar(this.tabBarBuilder('我的', 1, $r('app.media.ic_friend_sel'),
                    $r('app.media.ic_friend_normal')))
            }
            .width("100%")
            .height("100%")
            .divider({
                strokeWidth: '2vp',
                color: Color.Gray,
            })
            .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
            .scrollable(false)
            .vertical(false)
            .onChange((index: number) => {
                this.currentIndex = index
            })
        }
        .width("100%")
        .height("100%")
        .onReady((context: NavDestinationContext) => {
            this.pathStack = context.pathStack;
        })
    }
}

真机演示:

cke_55740.gif

修整后代码

@Entry
@Component
struct Index {
  @Provide('pageIndex') pageIndex: NavPathStack = new NavPathStack()
  collectController: CollectController = new CollectController()

  @State currentIndex: number = 0;
  @State menus: MenuItemType[] = [
    { icon: 'svg_home', text: '首页'},
    { icon: 'svg_find', text: '教程' },
    { icon: 'svg_collect', text: '收藏' },
    { icon: 'svg_me', text: '我的' },
  ]
  // 新增参数接收逻辑
  aboutToAppear(): void {
    const params = Router.getParams();
    if (params?.tabIndex !== undefined) {
      this.currentIndex = params.tabIndex
    }
    HttpComWrapper.getInstance().getCityResult()
    if (UserUtils.loginNoNot()) {
      HttpComWrapper.getInstance().getUserLevel()
    }
  }
  // 新增页面显示时参数监听
  onPageShow(): void {
    const params = Router.getParams();
    if (params?.tabIndex !== undefined) {
      this.currentIndex = params.tabIndex
    }
  }
  // 原有布局保持不变
  build() {
    Navigation(this.pageIndex) {
      Column() {
        Tabs({ barPosition: BarPosition.End, index: this.currentIndex }) {
          ForEach(this.menus, (item: MenuItemType, index: number) => {
            TabContent() {
              this.tabBuilderContent(index)
            }
            .tabBar(this.tabBuilderBar(item, index))
          })
        }
        .onChange((index: number) => {
          this.currentIndex = index
          // 原有逻辑...
        })
      }
    }
  }
}

子界面登录跳转逻辑

// 在登录按钮点击事件中实现
Button('登录')
  .onClick(() => {
    Router.clear()
    Router.replace({
      url: 'pages/Index',
      params: { tabIndex: 3 } // 对应"我的"页签
    })
  })

主界面接收参数

@Entry
@Component
struct Index {
  @State currentIndex: number = 0;

  aboutToAppear() {
    const params = router.getParams();
    if (params?.targetTab) {
      this.currentIndex = Number(params.targetTab);
    }
  }

  onPageShow() {
    const params = router.getParams();
    if (params?.targetTab) { // 防止页面恢复时状态丢失
      this.currentIndex = Number(params.targetTab);
    }
  }

  build() {
    // 原有界面结构不变...
    Tabs({ index: this.currentIndex })
      .onChange((index: number) => {
        this.currentIndex = index;
      })
  }
}

登录页面实现

// 在登录按钮点击事件中处理跳转
onLoginSuccess() {
  router.clear(); // 清除历史路由栈
  router.replaceUrl({
    url: 'pages/Index',
    params: { targetTab: 3 } // 指定跳转到"我的"Tab页
  }, (err) => {
    if (err) console.error('跳转失败:', err);
  });
}

返回的首页,再push到登录页

this.pageIndex.clear()
setTimeout(()=>{
  this.pageIndex.pushPathByName('login')
}, 300)

在HarmonyOS Next中,通过Router模块的pushUrl方法实现跳转。使用router.pushUrl并指定目标页面的URL,结合tab参数定位到具体标签页。例如:

import router from '@ohos.router';
router.pushUrl({
  url: 'pages/TabPage',
  params: { tab: 'home' }
});

在目标页面通过router.getParams获取参数并切换tab。

在HarmonyOS Next中,可以通过路由管理实现从子界面跳转到主界面指定Tab。建议使用router.clear()清除当前页面栈,然后通过router.pushUrl()跳转到主界面并传递参数指定目标Tab。

在你的代码中,可以在登录成功后调用:

import router from '@ohos.router';

// 登录成功后执行
router.clear();
router.pushUrl({
  url: 'pages/Index',
  params: { targetTab: 3 } // 3对应"我的"Tab
});

在主界面Index中,需要在aboutToAppear()onPageShow()生命周期中接收参数:

aboutToAppear(): void {
  const params = router.getParams();
  if (params && params['targetTab']) {
    this.currentIndex = params['targetTab'];
  }
  // 其他初始化代码...
}

这种方式会清空导航栈,确保返回主界面后无法通过返回键回到登录页,符合你的需求。

回到顶部