ArkUI Navigation 组件介绍与使用指南

什么是 Navigation 组件?

Navigation 是 ArkUI 中的导航组件,用于管理页面间的导航和路由。它提供了页面栈管理、导航栏定制、页面切换动画等功能,是构建多页面应用的核心组件。

Navigation 的核心概念

  1. 页面栈:采用栈结构管理页面,遵循"后进先出"原则
  2. 导航模式
    • NavigationMode.Stack:栈模式(默认)
    • NavigationMode.Split:分栏模式(平板等大屏设备)
  3. 导航栏:可自定义标题栏区域
  4. 路由:通过路径标识页面,支持参数传递

基本使用方法

简单页面导航

// 首页
@Entry
@Component
struct HomePage {
  build() {
    Navigation() {
      Column() {
        Text('首页')
          .fontSize(30)
          .margin(20)
        
        Button('跳转到详情页')
          .onClick(() => {
            router.pushUrl({
              url: 'pages/DetailPage'
            })
          })
      }
      .width('100%')
      .height('100%')
    }
    .title('首页')
  }
}

// 详情页
@Component
struct DetailPage {
  build() {
    Column() {
      Text('详情页内容')
        .fontSize(30)
        .margin(20)
      
      Button('返回')
        .onClick(() => {
          router.back()
        })
    }
    .width('100%')
    .height('100%')
  }
}

带参数的页面导航

// 列表页
@Entry
@Component
struct ListPage {
  private items: string[] = ['苹果', '香蕉', '橙子', '葡萄']

  build() {
    Navigation() {
      Column() {
        ForEach(this.items, (item) => {
          Button(item)
            .width('80%')
            .margin(5)
            .onClick(() => {
              router.pushUrl({
                url: 'pages/DetailPage',
                params: { name: item }
              })
            })
        })
      }
    }
    .title('水果列表')
  }
}

// 详情页
@Component
struct DetailPage {
  @State name: string = ''

  onPageShow() {
    this.name = router.getParams()?.['name'] || '未知'
  }

  build() {
    Column() {
      Text(`您选择了: ${this.name}`)
        .fontSize(30)
        .margin(20)
    }
  }
}

高级用法

自定义导航栏

@Entry
@Component
struct CustomNavPage {
  build() {
    Navigation() {
      Column() {
        Text('页面内容')
          .fontSize(20)
          .margin(20)
      }
    }
    .title('自定义标题')
    .subTitle('副标题')
    .hideBackButton(false)
    .toolBar({
      items: [
        {
          icon: $r('app.media.ic_share'),
          action: () => {
            // 分享操作
          }
        },
        {
          icon: $r('app.media.ic_favorite'),
          action: () => {
            // 收藏操作
          }
        }
      ]
    })
    .navBarWidth('80%')
    .navBarPosition(NavBarPosition.Start)
  }
}

分栏模式 (Split)

@Entry
@Component
struct SplitNavigationExample {
  private menus: string[] = ['首页', '分类', '发现', '我的']
  @State selectedIndex: number = 0

  build() {
    Navigation() {
      Column() {
        ForEach(this.menus, (menu, index) => {
          Button(menu)
            .width('100%')
            .stateEffect(this.selectedIndex === index)
            .onClick(() => {
              this.selectedIndex = index
            })
        })
      }
      .width('30%')
      .backgroundColor('#f5f5f5')

      Column() {
        if (this.selectedIndex === 0) {
          Text('首页内容').fontSize(24)
        } else if (this.selectedIndex === 1) {
          Text('分类内容').fontSize(24)
        } else if (this.selectedIndex === 2) {
          Text('发现内容').fontSize(24)
        } else {
          Text('个人中心').fontSize(24)
        }
      }
      .layoutWeight(1)
      .padding(20)
    }
    .mode(NavigationMode.Split)
    .minNavBarWidth(200)
    .maxNavBarWidth(300)
  }
}

页面切换动画

@Entry
@Component
struct AnimatedNavigation {
  build() {
    Navigation() {
      Column() {
        Button('淡入淡出效果')
          .onClick(() => {
            router.pushUrl({
              url: 'pages/DetailPage',
              transition: {
                type: RouteType.Push,
                curve: Curve.EaseInOut,
                duration: 300
              }
            })
          })
        
        Button('滑动效果')
          .onClick(() => {
            router.pushUrl({
              url: 'pages/DetailPage',
              transition: {
                type: RouteType.Push,
                slide: SlideEffect.Left
              }
            })
          })
      }
    }
  }
}

实际应用示例

电商应用导航

@Entry
@Component
struct ECommerceApp {
  @State currentTab: number = 0
  private tabs: string[] = ['首页', '分类', '购物车', '我的']

  build() {
    Navigation() {
      Column() {
        // 顶部导航栏
        Row() {
          ForEach(this.tabs, (tab, index) => {
            Button(tab)
              .borderRadius(0)
              .backgroundColor(this.currentTab === index ? '#ff5500' : '#ffffff')
              .fontColor(this.currentTab === index ? Color.White : Color.Black)
              .onClick(() => {
                this.currentTab = index
              })
          })
        }
        .width('100%')
        .height(50)
        
        // 内容区域
        Column() {
          if (this.currentTab === 0) {
            HomeTab()
          } else if (this.currentTab === 1) {
            CategoryTab()
          } else if (this.currentTab === 2) {
            CartTab()
          } else {
            ProfileTab()
          }
        }
        .layoutWeight(1)
      }
    }
    .hideToolBar(true)
    .hideTitleBar(true)
  }
}

@Component
struct HomeTab {
  build() {
    Scroll() {
      Column() {
        // 轮播图
        Swiper() {
          ForEach(['banner1', 'banner2', 'banner3'], (img) => {
            Image(img)
              .width('100%')
              .height(200)
          })
        }
        .indicator(true)
        .height(200)
        
        // 商品网格
        Grid() {
          ForEach(Array.from({ length: 12 }), (_, index) => {
            GridItem() {
              Column() {
                Image(`product_${index + 1}`)
                  .width(80)
                  .height(80)
                Text(`商品${index + 1}`)
                  .fontSize(14)
                Text('¥99')
                  .fontColor('#ff5500')
                  .fontSize(16)
              }
            }
          })
        }
        .columnsTemplate('1fr 1fr 1fr')
        .rowsGap(10)
        .columnsGap(10)
        .margin(10)
      }
    }
  }
}

新闻应用导航

@Entry
@Component
struct NewsApp {
  @State currentChannel: string = '推荐'
  private channels: string[] = ['推荐', '热点', '科技', '娱乐', '体育']

  build() {
    Navigation() {
      Column() {
        // 频道导航
        Scroll({ scrollable: ScrollDirection.Horizontal }) {
          Row() {
            ForEach(this.channels, (channel) => {
              Button(channel)
                .margin({ right: 15 })
                .stateEffect(this.currentChannel === channel)
                .onClick(() => {
                  this.currentChannel = channel
                })
            })
          }
          .padding(10)
        }
        .scrollBar(BarState.Off)
        
        // 新闻列表
        Scroll() {
          Column() {
            ForEach(Array.from({ length: 10 }), (_, index) => {
              Column() {
                Text(`${this.currentChannel}】新闻标题 ${index + 1}`)
                  .fontSize(18)
                  .fontWeight(FontWeight.Bold)
                  .margin({ bottom: 5 })
                
                Text('新闻摘要内容...')
                  .fontSize(14)
                  .fontColor('#666666')
                  .margin({ bottom: 10 })
                
                Divider()
              }
              .margin({ top: 10, left: 15, right: 15 })
              .onClick(() => {
                router.pushUrl({
                  url: 'pages/NewsDetail',
                  params: { id: index + 1 }
                })
              })
            })
          }
        }
        .layoutWeight(1)
      }
    }
    .title('新闻资讯')
    .toolBar({
      items: [
        {
          icon: $r('app.media.ic_search'),
          action: () => {
            router.pushUrl({
              url: 'pages/SearchPage'
            })
          }
        }
      ]
    })
  }
}

注意事项

  1. 页面生命周期

    • onPageShow:页面显示时触发
    • onPageHide:页面隐藏时触发
    • onBackPress:返回按钮点击时触发(可拦截返回操作)
  2. 路由管理

    • 使用 router.pushUrl 导航到新页面
    • 使用 router.back 返回上一页
    • 使用 router.replaceUrl 替换当前页面
    • 使用 router.clear 清空页面栈
  3. 性能优化

    • 避免在导航栏中使用复杂组件
    • 对于不常变化的页面考虑使用缓存
    • 合理使用分栏模式提升大屏设备体验
  4. 兼容性考虑

    • 分栏模式在大屏设备上效果更好
    • 确保导航结构在小屏设备上也能良好工作

Navigation 组件是构建复杂应用导航系统的基础,合理使用可以创建直观、高效的用户导航体验。在实际开发中,可以根据应用需求结合 Tabs、SideBar 等组件构建更丰富的导航结构。

Logo

惟楚有才,于斯为盛。欢迎来到长沙!!! 茶颜悦色、臭豆腐、CSDN和你一个都不能少~

更多推荐