跳过主要内容
返回插件
@capgo/capacitor-native-navigation
教程
@capgo/capacitor-native-navigation

原生导航

在全屏 Capacitor WebView 上渲染原生导航栏、标签栏和过渡壳

演示

Animated WebP 演示

原生导航栏、选项卡选择、SVG 图标和样式选项呈现为 Animated WebP 演示

源资产
原生导航栏、选项卡和 WebView 内容的动画原生 shell 演示
原生 shell
选项卡选择、推送过渡和原生后退的动画原生导航栏点击流
点击流
动态原生 SVG 图标示例,展示内联 SVG 图标、原生颜色、标签和选项卡选择
SVG 图标
动态原生导航选项示例,展示动态颜色、选中标签、徽章和缩放过渡
样式选项

指南

原生导航教程

在设备上测试

下载 Capgo 应用程序,然后扫描二维码 code。

原生导航插件预览二维码code

使用@capgo/capacitor-native-navigation

@capgo/capacitor-native-navigation 渲染原生顶部导航栏、底部标签栏和路由切换壳,覆盖在一个全屏Capacitor WebView 上。您的 Web 框架仍然拥有路由和内容,而原生则拥有应用框架。

安装并同步

npm install @capgo/capacitor-native-navigation
npx cap sync

配置原生框架

import { NativeNavigation } from '@capgo/capacitor-native-navigation';

await NativeNavigation.configure({
  contentInsetMode: 'css',
  animationDuration: 360,
  colors: {
    tint: '#0f172a',
    inactiveTint: '#64748b',
  },
});

渲染原生导航栏

await NativeNavigation.setNavbar({
  title: 'Inbox',
  subtitle: 'Native chrome',
  transparent: true,
  backButton: { visible: false },
  rightItems: [
    {
      id: 'compose',
      title: 'Compose',
      icon: {
        svg: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 20h9"/><path d="M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z"/></svg>',
      },
    },
  ],
});

渲染原生标签栏

await NativeNavigation.setTabbar({
  selectedId: 'inbox',
  labelVisibilityMode: 'selected',
  icons: true,
  colors: {
    dynamic: true,
    tint: '#0f172a',
    inactiveTint: '#64748b',
  },
  tabs: [
    {
      id: 'inbox',
      title: 'Inbox',
      icon: {
        svg: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 4h16v16H4z"/><path d="m4 13 4 4h8l4-4"/></svg>',
      },
    },
    {
      id: 'search',
      title: 'Search',
      icon: {
        svg: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="7"/><path d="m20 20-3-3"/></svg>',
      },
    },
  ],
});

将原生事件连接到您的路由器

原生栏发射意图。您的路由器仍然执行路由切换:

await NativeNavigation.addListener('navbarBack', () => {
  router.back();
});

await NativeNavigation.addListener('navbarItemTap', ({ id }) => {
  if (id === 'compose') router.push('/compose');
});

await NativeNavigation.addListener('tabSelect', ({ id }) => {
  router.push(`/${id}`);
});

路由切换动画

在您的正常 Web 路由更新周围使用一个过渡事务:

const transition = await NativeNavigation.beginTransition({
  direction: 'forward',
});

router.push('/message/42');
await router.ready?.();

await NativeNavigation.setNavbar({
  title: 'Message',
  backButton: { visible: true, title: 'Inbox' },
});

await NativeNavigation.finishTransition({
  id: transition.id,
  direction: 'forward',
});

添加缩放过渡

在从卡片、网格项或媒体预览打开的路由中使用缩放辅助功能。

import { beginZoomTransition, finishZoomTransition } from '@capgo/capacitor-native-navigation';

const card = document.querySelector('[data-message-card]');
if (card) {
  const transition = await beginZoomTransition(card, { cornerRadius: 18 });

  router.push('/message/42');
  await router.ready?.();

  await NativeNavigation.setNavbar({
    title: 'Message',
    backButton: { visible: true, title: 'Inbox' },
  });

  await finishZoomTransition(undefined, {
    id: transition.id,
    cornerRadius: 18,
  });
}

用原生边距填充内容

contentInsetModecss,插件会为原生栏写入CSS变量:

.page {
  padding-top: var(--cap-native-navigation-top);
  padding-bottom: var(--cap-native-navigation-bottom);
}

图标选择

图标是原生描述符,而不是React或Vue节点。使用SVG时不想打包原生资产时使用SVG:

const icon = {
  svg: '<svg viewBox="0 0 24 24"><path d="M3 10.5 12 3l9 7.5"/></svg>',
  template: true,
  ios: { sfSymbol: 'house.fill' },
  android: { resource: 'ic_menu_view' },
};

内联SVG支持 path, line, polyline, polygon, circlerect,这涵盖了常见的图标集,如Lucide和Feather。

结合@capgo/capacitor-transitions

使用原生导航栏来实现原生navbar、tabbar、安全区域 insets 和原生意图事件。使用 @capgo/capacitor-transitions 来实现 WebView 页面堆栈在原生chrome下面。

npm install @capgo/capacitor-native-navigation @capgo/capacitor-transitions
npx cap sync

初始化两个包一次:

import { NativeNavigation } from '@capgo/capacitor-native-navigation';
import '@capgo/capacitor-transitions';
import { initTransitions, setupRouterOutlet, setDirection } from '@capgo/capacitor-transitions/react';

initTransitions({ platform: 'auto' });

const outlet = document.querySelector('cap-router-outlet');
if (outlet) {
  setupRouterOutlet(outlet, { platform: 'auto', swipeGesture: 'auto' });
}

await NativeNavigation.configure({
  contentInsetMode: 'css',
});

保持页面的转场动画在页面上,避免重复的web导航栏:

<cap-router-outlet platform="auto" swipe-gesture="auto">
  <cap-page>
    <cap-content slot="content" fullscreen>
      <main class="page">Inbox content</main>
    </cap-content>
  </cap-page>
</cap-router-outlet>

驱动两个包的路由动作:

async function openMessage(id: string) {
  setDirection('forward');
  await router.push(`/messages/${id}`);
  await NativeNavigation.setNavbar({
    title: 'Message',
    backButton: { visible: true, title: 'Inbox' },
  });
}

await NativeNavigation.addListener('navbarBack', () => {
  setDirection('back');
  router.back();
});

await NativeNavigation.addListener('tabSelect', ({ id }) => {
  setDirection('root');
  router.push(`/${id}`);
});

选择每次路由变化时使用一个动画层。让 @capgo/capacitor-transitions 正常页面推入使用动画,仅使用原生导航的缩放帮助来实现共享元素或缩放路由。

完整参考文档

继续使用@capgo/capacitor-native-navigation

如果您正在使用 使用@capgo/capacitor-native-navigation 规划原生媒体和界面行为,连接它与 @capgo/capacitor-native-navigation 查看@capgo/capacitor-native-navigation的实现细节在 Getting Started 查看Getting Started的实现细节在 使用@capgo/capacitor-live-activities 原生能力的@capgo/capacitor-live-activities @capgo/capacitor-live-activities 查看@capgo/capacitor-live-activities的实现细节在 使用@capgo/capacitor-video-player 为native能力在使用@capgo/capacitor-video-player中。