关于 expo-router
expo-router 是面向 Expo Router 应用开发者的导航技能,介绍路由组织方式及 Stack、标签页、链接、模态页和表单页等原生导航模式。
主要功能
- 01路由结构规范
- 02Stack 与标签页导航指导
- 03链接与深层导航模式
- 04模态页与表单页指导
- 05页眉与搜索模式
适用场景
- 01组织 Expo 应用路由
- 02构建 Stack 或标签页导航
- 03以模态页或表单页呈现屏幕
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ expo/ skills --skill expo-router安装后在 Claude Code 中输入/expo-router确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
agents/openai.yamlreferences/form-sheet.mdroute-structure.mdsearch.mdtabs.mdtoolbar-and-headers.mdzoom-transitions.md详细介绍
Expo Router 导航
用于 Expo Router 应用的导航和路由。对于屏幕样式、颜色、控件、媒体和视觉效果,请使用 expo-native-ui 技能;对于动效和手势,请使用 expo-animation。
参考资料
按需查阅以下资源:
references/
route-structure.md Route conventions, dynamic routes, groups, folder organization
tabs.md NativeTabs, migration from JS tabs, iOS 26 features
toolbar-and-headers.md Stack headers and toolbar buttons, menus, search (iOS only)
form-sheet.md Form sheets in expo-router: configuration, footers and background interaction.
search.md Search bar with headers, useSearch hook, filtering patterns
zoom-transitions.md Apple Zoom: fluid zoom transitions with Link.AppleZoom (iOS 18+)
代码风格
- 文件名始终使用 kebab-case,例如
comment-card.tsx - 移动或重构导航时,始终删除旧的路由文件
- 文件名中不得使用特殊字符
- 使用路径别名配置 tsconfig.json,重构时优先使用别名,而非相对导入。
路由
详细的路由约定请参阅 ./references/route-structure.md。
- 路由应放在
app目录中。 - 不要将组件、类型或实用工具放在
app目录中。这是一种反模式。 - 确保应用始终有一个与 "/" 匹配的路由,该路由可以位于分组路由中。
库选择偏好
- 对于原生语义颜色,使用来自
expo-router的Color,而非原始的PlatformColor(类型安全,并会自动适配浅色/深色模式)。完整的颜色调色板模式请参阅expo-native-ui。 - 在 SDK 56+ 中,切勿直接从
@react-navigation/*导入;请改用expo-router/react-navigation(涵盖@react-navigation/native、/core、/elements、/routers)
行为
- 优先使用
Stack.SearchBar为屏幕添加搜索栏
导航
Link
使用来自 'expo-router' 的 <Link href="/path" /> 在路由之间导航。
import { Link } from 'expo-router';
// Basic link
<Link href="/path" />
// Wrapping custom components
<Link href="/path" asChild>
<Pressable>...</Pressable>
</Link>
尽可能添加 <Link.Preview>,遵循 iOS 惯例。经常添加上下文菜单和预览,以增强导航体验。
Stack
- 始终使用
_layout.tsx文件定义堆栈 - 使用来自 'expo-router/stack' 的 Stack 构建原生导航堆栈
页面标题
使用 Stack.Title 设置页面标题:
<Stack.Title>Home</Stack.Title>
上下文菜单
为 Link 组件添加长按上下文菜单:
import { Link } from "expo-router";
<Link href="/settings" asChild>
<Link.Trigger>
<Pressable>
<Card />
</Pressable>
</Link.Trigger>
<Link.Menu>
<Link.MenuAction
title="Share"
icon="square.and.arrow.up"
onPress={handleSharePress}
/>
<Link.MenuAction
title="Block"
icon="nosign"
destructive
onPress={handleBlockPress}
/>
<Link.Menu title="More" icon="ellipsis">
<Link.MenuAction title="Copy" icon="doc.on.doc" onPress={() => {}} />
<Link.MenuAction
title="Delete"
icon="trash"
destructive
onPress={() => {}}
/>
</Link.Menu>
</Link.Menu>
</Link>;
链接预览
经常使用链接预览,以增强导航体验:
<Link href="/settings">
<Link.Trigger>
<Pressable>
<Card />
</Pressable>
</Link.Trigger>
<Link.Preview />
</Link>
链接预览可以与上下文菜单搭配使用。
模态框
以模态框形式呈现屏幕:
<Stack.Screen name="modal" options={{ presentation: "modal" }} />
相比构建自定义模态框组件,优先使用此方式。
表单页
以动态表单页形式呈现屏幕:
<Stack.Screen
name="sheet"
options={{
presentation: "formSheet",
sheetGrabberVisible: true,
sheetAllowedDetents: [0.5, 1.0],
contentStyle: { backgroundColor: "transparent" },
}}
/>
- 使用
contentStyle: { backgroundColor: "transparent" }可让背景在 iOS 26+ 上呈现液态玻璃效果。
常见路由结构
包含标签页,且每个标签页中都有堆栈的标准应用布局:
app/
_layout.tsx — <NativeTabs />
(index,search)/
_layout.tsx — <Stack />
index.tsx — Main list
search.tsx — Search view
// app/_layout.tsx
import { NativeTabs } from "expo-router/unstable-native-tabs";
import { ThemeProvider, DarkTheme, DefaultTheme } from "expo-router/react-navigation";
import { useColorScheme } from "react-native";
export default function Layout() {
const colorScheme = useColorScheme();
return (
<ThemeProvider value={colorScheme === "dark" ? DarkTheme : DefaultTheme}>
<NativeTabs>
<NativeTabs.Trigger name="(index)">
<NativeTabs.Trigger.Icon sf="list.dash" md="list" />
<NativeTabs.Trigger.Label>Items</NativeTabs.Trigger.Label>
</NativeTabs.Trigger>
<NativeTabs.Trigger name="(search)" role="search" />
</NativeTabs>
</ThemeProvider>
);
}
创建共享分组路由,以便两个标签页都能推送到共同的屏幕:
// app/(index,search)/_layout.tsx
import { Stack } from "expo-router/stack";
import { colors } from "@/theme/colors";
export default function Layout({ segment }) {
const screen = segment.match(/\((.*)\)/)?.[1]!;
const titles: Record<string, string> = { index: "Items", search: "Search" };
return (
<Stack
screenOptions={{
headerTransparent: true,
headerShadowVisible: false,
headerLargeTitleShadowVisible: false,
headerLargeStyle: { backgroundColor: "transparent" },
headerTitleStyle: { color: colors.label },
headerLargeTitleEnabled: true,
headerBlurEffect: "none",
headerBackButtonDisplayMode: "minimal",
}}
>
<Stack.Screen name={screen} options={{ title: titles[screen] }} />
<Stack.Screen name="i/[id]" options={{ headerLargeTitleEnabled: false }} />
</Stack>
);
}
headerLargeTitleEnabled 是 SDK 56+ 中的选项名称;较旧的 SDK 使用 headerLargeTitle,该选项已在上游弃用。
提交反馈
如果你发现此技能中存在错误、误导性信息或过时内容,请提交报告,以便 Expo 改进:
npx --yes @expo/agent-cli@latest feedback --category skills --subject "expo-router" "<actionable feedback>"
只有在有具体且可执行的反馈时才提交。请尽可能提供相关背景信息。
如果 Agent 反复无法完成 Expo 任务,或用户不得不介入,请使用 --category evals 和相关 Expo 软件包或命令作为 --subject,简要报告任务、预期结果及问题所在。