【鸿蒙开发】Tabs 实现导航条功能

2025-08-31 21:07:27

本文是工作中用到的笔记📒,记录使用 Tabs 组件实现导航条功能。

目录:

导航条基础使用

导航条默认出现在页面顶部。

@Entry
@Component
struct TestTabs {
  build() {
    Tabs() {
      TabContent() { Text('首页内容') }.tabBar('首页')
      TabContent() { Text('我的内容') }.tabBar('我的')
    }
  }
}

设置底部导航条

微信的导航条默认就在底部显示。

@Entry
@Component
struct TestTabs {
  build() {
    Tabs({ barPosition: BarPosition.End }) {
      TabContent() {
        Text('首页内容')
      }.tabBar('首页')
      TabContent() {
        Text('我的内容')
      }.tabBar('我的')
    }
  }
}

设置侧边导航条

外卖平台的点单页面导航条默认在左侧显示。

@Entry
@Component
struct TestTabs {
  build() {
    // 当 vertical 为 true 时,Start 在左边,End 在右边
    Tabs({ barPosition: BarPosition.Start }) {
      TabContent() {
        Text('首页内容')
      }.tabBar('首页')
      TabContent() {
        Text('我的内容')
      }.tabBar('我的')
    }
    // 垂直显示
    .vertical(true)
    // 手动固定导航条宽度
    .barWidth(100)
  }
}

自定义导航条内容

下面示例代码中的图标地址需要自行替换。

@Entry
@Component
struct TestTabs {
  // 控制导航栏切换
  @State currentIndex: number = 0;
  // 控制导航对应的视图切换
  private tabsController : TabsController = new TabsController();

  // 自定义导航内容
  @Builder
  TabBuilder(title: string, index: number, img: Resource, activeImg: Resource) {
    Column() {
      Image(this.currentIndex === index ? activeImg : img)
        .width(25)
        .height(25)
      Text(title).fontColor(this.currentIndex === index ? '#1698CE' : '#6B6B6B')
    }
    .onClick(() => {
      this.currentIndex = index;
      this.tabsController.changeIndex(index)
    })
  }

  build() {
    Tabs({ barPosition: BarPosition.End, controller: this.tabsController }) {
      TabContent() {
        Text('首页内容')
      }.tabBar(this.TabBuilder('首页', 0, $r('app.media.ic_home_normal'), $r('app.media.ic_home_selected')))
      TabContent() {
        Text('我的内容')
      }.tabBar(this.TabBuilder('我的', 1, $r('app.media.ic_mine_normal'), $r('app.media.ic_mine_selected')))
    }
  }
}

切换导航条时进行初始化数据

导航对应的页面比较复杂时,会将导航内容写成一个独立的组件,如下代码,Home() 和 Mine() 分别是两个导航对应的页面。

@Entry
@Component
struct TestTabs {
  build() {
    Tabs({ barPosition: BarPosition.End }) {
      TabContent() {
        Home()
      }.tabBar('首页')
      TabContent() {
        Mine()
      }.tabBar('我的')
    }
  }
}

@Component
struct Home {
  aboutToAppear(): void {
    console.log('Home component load ...')
    // 每次切换到首页视图,都想要查询数据
  }

  build() {
    Text('首页内容')
  }
}

@Component
struct Mine {
  build() {
    Text('我的内容')
  }
}

此时有一个问题:每次进入导航条对应的页面,需要做一些初始化数据的操作,最开始想到的是 aboutToAppear(),含义是组件第一次加载时触发,测试时发现来回切换导航条,aboutToAppear() 只会触发一次。

原因:
🐟 比如当前位于A导航条,A导航条对应的页面第一次加载时会触发 aboutToAppear();
🐟 现在从 A 导航条切换到 B 导航条,A 导航对应的页面隐藏起来,并不是直接销毁;
🐟 从 B 导航条再切换回 A 导航条时,由于 A 导航条对应的页面之前已经存在了,此时是不会触发 A 导航条对应页面的 aboutToAppear() 函数的。

这里介绍两个解决方法:
☁️ 导航条数目很少时,使用 TabContent().onWillShow() 监听切换触发事件;
☁️ 导航条数目很多时,使用 Tabs().onChange() 监听切换触发事件。

@Entry
@Component
struct TestTabs {
  build() {
    Tabs({ barPosition: BarPosition.End }) {
      TabContent() {
        Home()
      }
      .tabBar('首页')
      .onWillShow(() => {
        console.log('每次切换到首页导航条时都会触发...')
      })
      TabContent() {
        Mine()
      }.tabBar('我的')
      .onWillShow(() => {
        console.log('每次切换到我的导航条时都会触发...')
      })
    }
    .onChange((index: number) => {
      console.log('当前切换的导航条下标', index)
    })
  }
}

@Component
struct Home {
  build() {
    Text('首页内容')
  }
}

@Component
struct Mine {
  build() {
    Text('我的内容')
  }
}

现在可以监控导航条切换,但是最终目的是想要改变 Home 内部的变量值,可以使用 @StorageLink 装饰器,在 TestTabs 和 Home 中都添加变量定义,不管哪一边修改变量值,另一边的变量值也会同步改变。

完整示例代码如下:

@Entry
@Component
struct TestTabs {
  @StorageLink('productList') productList: string[] = [];

  build() {
    Tabs({ barPosition: BarPosition.End }) {
      TabContent() {
        Home()
      }
      .tabBar('首页')
      .onWillShow(() => {
        console.log('每次切换到首页导航条时都会触发...')
        // 模拟异步请求
        setTimeout(() => {
          // 修改 TestTabs 中的 productList 变量值
          // Home 中的 productList 值会自动更新
          this.productList = [ 'a', 'b', 'c' ];
        }, 3000)
      })
      TabContent() {
        Mine()
      }.tabBar('我的')
      .onWillShow(() => {
        console.log('每次切换到我的导航条时都会触发...')
      })
    }
    .onChange((index: number) => {
      console.log('当前切换的导航条下标', index)
    })
  }
}

@Component
struct Home {
  @StorageLink('productList') productList: string[] = [];

  build() {
    Column() {
      Text('首页内容')
      ForEach(this.productList, (item: string) => {
        Text(`Product ${item}`)
      })
    }
  }
}

@Component
struct Mine {
  build() {
    Text('我的内容')
  }
}

返回首页

本文总阅读量  次
皖ICP备17026209号-3
总访问量: 
总访客量: