配置链接
在本指南中,我们将配置 React Navigation 来处理外部链接。如果你想要:
¥In this guide, we will configure React Navigation to handle external links. This is necessary if you want to:
-
处理 Android 和 iOS 上的 React Native 应用中的深层链接
¥Handle deep links in React Native apps on Android and iOS
-
在网络上使用时启用浏览器中的 URL 集成
¥Enable URL integration in browser when using on web
在继续之前,请确保你的应用中有 配置的深层链接。如果你有 Android 或 iOS 应用,请记住指定 prefixes
选项。
¥Make sure that you have configured deep links in your app before proceeding. If you have an Android or iOS app, remember to specify the prefixes
option.
- Static
- Dynamic
Navigation
组件接受 linking
prop,这使得处理传入链接更加容易:
¥The Navigation
component accepts a linking
prop that makes it easier to handle incoming links:
import { createStaticNavigation } from '@react-navigation/native';
const linking = {
enabled: 'auto' /* Automatically generate paths for all screens */,
prefixes: [
/* your linking prefixes */
],
};
function App() {
return (
<Navigation
linking={linking}
fallback={<Text>Loading...</Text>}
/>
);
}
const Navigation = createStaticNavigation(RootStack);
NavigationContainer
接受 linking
属性,可以更轻松地处理传入链接。你可以在 linking
属性中指定的两个最重要的属性是 prefixes
和 config
:
¥The NavigationContainer
accepts a linking
prop that makes it easier to handle incoming links. The 2 of the most important properties you can specify in the linking
prop are prefixes
and config
:
import { NavigationContainer } from '@react-navigation/native';
const linking = {
prefixes: [
/* your linking prefixes */
],
config: {
/* configuration for matching screens with paths */
},
};
function App() {
return (
<NavigationContainer
linking={linking}
fallback={<Text>Loading...</Text>}
>
{/* content */}
</NavigationContainer>
);
}
当你指定 linking
属性时,React Navigation 将自动处理传入链接。在 Android 和 iOS 上,它将使用 React Native 的 Linking
模块 来处理传入链接,无论是在使用链接打开应用时,还是在打开应用时收到新链接时。在 Web 上,它将使用 历史 API 将 URL 与浏览器同步。
¥When you specify the linking
prop, React Navigation will handle incoming links automatically. On Android and iOS, it'll use React Native's Linking
module to handle incoming links, both when the app was opened with the link, and when new links are received when the app is open. On the Web, it'll use the History API to sync the URL with the browser.
目前似乎存在 bug (facebook/react-native#25675),导致它在 Android 上永远无法解决。我们添加了超时以避免永远卡住,但这意味着在某些情况下可能无法处理链接。
¥Currently there seems to be bug (facebook/react-native#25675) which results in it never resolving on Android. We add a timeout to avoid getting stuck forever, but it means that the link might not be handled in some cases.
你还可以传递一个 fallback
prop,该 prop 控制 React Navigation 尝试解析初始深层链接 URL 时显示的内容。
¥You can also pass a fallback
prop that controls what's displayed when React Navigation is trying to resolve the initial deep link URL.
前缀
¥Prefixes
如果你配置了 通用链接 或 安卓应用链接,则 prefixes
选项可用于指定自定义方案(例如 mychat://
)以及主机名和域名(例如 https://mychat.com
)。
¥The prefixes
option can be used to specify custom schemes (e.g. mychat://
) as well as host & domain names (e.g. https://mychat.com
) if you have configured Universal Links or Android App Links.
例如:
¥For example:
const linking = {
prefixes: ['mychat://', 'https://mychat.com'],
};
请注意,Web 上不支持 prefixes
选项。主机名和域名将根据浏览器中的网站 URL 自动确定。如果你的应用仅在 Web 上运行,那么你可以从配置中省略此选项。
¥Note that the prefixes
option is not supported on Web. The host & domain names will be automatically determined from the Website URL in the browser. If your app runs only on Web, then you can omit this option from the config.
多个子域
¥Multiple subdomains
要匹配关联域的所有子域,你可以通过前缀 *
来指定通配符。在特定域的开始之前。请注意,由于星号后面有句点,因此 *.mychat.com
的条目与 mychat.com
不匹配。要启用 *.mychat.com
和 mychat.com
的匹配,你需要为每个提供单独的前缀条目。
¥To match all subdomains of an associated domain, you can specify a wildcard by prefixing *
. before the beginning of a specific domain. Note that an entry for *.mychat.com
does not match mychat.com
because of the period after the asterisk. To enable matching for both *.mychat.com
and mychat.com
, you need to provide a separate prefix entry for each.
const linking = {
prefixes: ['mychat://', 'https://mychat.com', 'https://*.mychat.com'],
};
过滤某些路径
¥Filtering certain paths
有时我们可能不想处理所有传入链接。例如,我们可能希望过滤掉用于身份验证(例如 expo-auth-session
)或其他目的的链接,而不是导航到特定屏幕。
¥Sometimes we may not want to handle all incoming links. For example, we may want to filter out links meant for authentication (e.g. expo-auth-session
) or other purposes instead of navigating to a specific screen.
为此,你可以使用 filter
选项:
¥To achieve this, you can use the filter
option:
const linking = {
prefixes: ['mychat://', 'https://mychat.com'],
filter: (url) => !url.includes('+expo-auth-session'),
};
Web 上不支持此功能,因为我们始终需要处理页面的 URL。
¥This is not supported on Web as we always need to handle the URL of the page.
子路径下的应用
¥Apps under subpaths
如果你的应用托管在子路径下,你可以在 config
的顶层指定子路径。例如,如果你的应用托管在 https://mychat.com/app
上,你可以将 path
指定为 app
:
¥If your app is hosted under a subpath, you can specify the subpath at the top-level of the config
. For example, if your app is hosted at https://mychat.com/app
, you can specify the path
as app
:
const linking = {
prefixes: ['mychat://', 'https://mychat.com'],
config: {
path: 'app',
// ...
},
};
由于这不属于屏幕,因此无法在此处指定参数,例如 app/:id
将不起作用。
¥It's not possible to specify params here since this doesn't belong to a screen, e.g. app/:id
won't work.
将路径映射到路由名称
¥Mapping path to route names
- Static
- Dynamic
如果你在 linking
prop 中指定 enabled: 'auto'
,React Navigation 将自动为所有屏幕生成路径。例如,如果导航器中有一个 Profile
屏幕,它将自动为其生成一个路径作为 profile
。
¥If you specify enabled: 'auto'
in the linking
prop, React Navigation will automatically generate paths for all screens. For example, if you have a Profile
screen in the navigator, it'll automatically generate a path for it as profile
.
如果你希望手动处理配置,或者想要覆盖特定屏幕的生成路径,则可以在导航器中屏幕旁边指定 linking
属性以将路径映射到屏幕。例如:
¥If you wish to handle the configuration manually, or want to override the generated path for a specific screen, you can specify linking
property next to the screen in the navigator to map a path to a screen. For example:
const RootStack = createStackNavigator({
screens: {
Profile: {
screen: ProfileScreen,
linking: {
path: 'user',
},
},
Chat: {
screen: ChatScreen,
linking: {
path: 'feed/:sort',
},
},
},
});
在此示例中:
¥In this example:
-
Chat
屏幕使用参数sort
处理 URL/feed
(例如/feed/latest
-Chat
屏幕将接收带有值latest
的参数sort
)。¥
Chat
screen that handles the URL/feed
with the paramsort
(e.g./feed/latest
- theChat
screen will receive a paramsort
with the valuelatest
). -
Profile
屏幕处理 URL/user
。¥
Profile
screen that handles the URL/user
.
类似地,当你有嵌套导航器时,你可以为导航器中的屏幕指定 linking
属性来处理嵌套屏幕的路径:
¥Similarly, when you have a nested navigator, you can specify the linking
property for the screens in the navigator to handle the path for the nested screens:
const HomeTabs = createBottomTabNavigator({
screens: {
Home: {
screen: HomeScreen,
linking: {
path: 'home',
},
},
Settings: {
screen: SettingsScreen,
linking: {
path: 'settings',
},
},
},
});
const RootStack = createStackNavigator({
screens: {
HomeTabs: {
screen: HomeTabs,
},
Profile: {
screen: ProfileScreen,
linking: {
path: 'user',
},
},
Chat: {
screen: ChatScreen,
linking: {
path: 'feed/:sort',
},
},
},
});
在上面的例子中,处理以下路径格式:
¥In the above example, the following path formats are handled:
-
/home
导航到HomeTabs
->Home
屏幕¥
/home
navigates to theHomeTabs
->Home
screen -
/settings
导航到HomeTabs
->Settings
屏幕¥
/settings
navigates to theHomeTabs
->Settings
screen -
/user
导航到Profile
屏幕¥
/user
navigates to theProfile
screen -
/feed/:sort
使用参数sort
导航到Chat
屏幕¥
/feed/:sort
navigates to theChat
screen with the paramsort
自动路径生成如何工作?
¥How does automatic path generation work?
使用 enabled: 'auto'
自动路径生成时,适用以下规则:
¥When using automatic path generation with enabled: 'auto'
, the following rules are applied:
-
具有显式
linking
属性的屏幕不用于路径生成,将按原样添加。¥Screens with an explicit
linking
property are not used for path generation and will be added as-is. -
屏幕名称将从
PascalCase
转换为kebab-case
以用作路径(例如NewsFeed
->news-feed
)。¥Screen names will be converted from
PascalCase
tokebab-case
to use as the path (e.g.NewsFeed
->news-feed
). -
除非屏幕具有明确的空路径(
path: ''
)用作主页,否则遇到的第一个叶屏幕将用作主页。¥Unless a screen has explicit empty path (
path: ''
) to use for the homepage, the first leaf screen encountered will be used as the homepage. -
路径生成仅处理叶屏幕,即不为包含嵌套导航器的屏幕生成路径。仍然可以使用显式
linking
属性为它们指定路径。¥Path generation only handles leaf screens, i.e. no path is generated for screens containing nested navigators. It's still possible to specify a path for them with an explicit
linking
property.
假设我们有以下导航结构:
¥Let's say we have the following navigation structure:
const HomeTabs = createBottomTabNavigator({
screens: {
Home: {
screen: HomeScreen,
},
Settings: {
screen: SettingsScreen,
},
},
});
const RootStack = createStackNavigator({
screens: {
HomeTabs: {
screen: HomeTabs,
},
Profile: {
screen: ProfileScreen,
},
Chat: {
screen: ChatScreen,
},
},
});
使用自动路径生成,将生成以下路径:
¥With automatic path generation, the following paths will be generated:
-
/
导航到HomeTabs
->Home
屏幕¥
/
navigates to theHomeTabs
->Home
screen -
/settings
导航到HomeTabs
->Settings
屏幕¥
/settings
navigates to theHomeTabs
->Settings
screen -
/profile
导航到Profile
屏幕¥
/profile
navigates to theProfile
screen -
/chat
导航到Chat
屏幕¥
/chat
navigates to theChat
screen
如果 URL 包含查询字符串,它将作为参数传递给屏幕。例如,URL /profile?user=jane
将把 user
参数传递给 Profile
屏幕。
¥If the URL contains a query string, it'll be passed as params to the screen. For example, the URL /profile?user=jane
will pass the user
param to the Profile
screen.
如果你指定 linking
选项,默认情况下,React Navigation 将在解析 URL 时使用路径段作为路由名称。但是,直接将路径段转换为路由名称可能不是预期的行为。
¥If you specify a linking
option, by default React Navigation will use the path segments as the route name when parsing the URL. However, directly translating path segments to route names may not be the expected behavior.
你可以在 linking
中指定 config
选项来控制如何解析深层链接以满足你的需求。配置应指定路由名称和路径模式之间的映射:
¥You can specify the config
option in linking
to control how the deep link is parsed to suit your needs. The config should specify the mapping between route names and path patterns:
const config = {
screens: {
Chat: 'feed/:sort',
Profile: 'user',
},
};
在此示例中:
¥In this example:
-
Chat
屏幕使用参数sort
处理 URL/feed
(例如/feed/latest
-Chat
屏幕将接收带有值latest
的参数sort
)。¥
Chat
screen that handles the URL/feed
with the paramsort
(e.g./feed/latest
- theChat
screen will receive a paramsort
with the valuelatest
). -
Profile
屏幕处理 URL/user
。¥
Profile
screen that handles the URL/user
.
然后可以将配置选项通过 linking
属性传递给容器:
¥The config option can then be passed in the linking
prop to the container:
import { NavigationContainer } from '@react-navigation/native';
const config = {
screens: {
Chat: 'feed/:sort',
Profile: 'user',
},
};
const linking = {
prefixes: ['https://mychat.com', 'mychat://'],
config,
};
function App() {
return (
<NavigationContainer linking={linking} fallback={<Text>Loading...</Text>}>
{/* content */}
</NavigationContainer>
);
}
配置对象必须与你的应用的导航结构匹配。例如,上面的配置是如果根导航器中有 Chat
和 Profile
屏幕:
¥The config object must match the navigation structure for your app. For example, the above configuration is if you have Chat
and Profile
screens in the navigator at the root:
function App() {
return (
<Stack.Navigator>
<Stack.Screen name="Chat" component={ChatScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
);
}
如果你的 Chat
屏幕位于嵌套导航器内,我们需要考虑到这一点。例如,考虑以下结构,其中 Profile
屏幕位于根目录,但 Chat
屏幕嵌套在 Home
内:
¥If your Chat
screen is inside a nested navigator, we'd need to account for that. For example, consider the following structure where your Profile
screen is at the root, but the Chat
screen is nested inside Home
:
function App() {
return (
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
);
}
function HomeScreen() {
return (
<Tab.Navigator>
<Tab.Screen name="Chat" component={ChatScreen} />
</Tab.Navigator>
);
}
对于上述结构,我们的配置将如下所示:
¥For the above structure, our configuration will look like this:
const config = {
screens: {
Home: {
screens: {
Chat: 'feed/:sort',
},
},
Profile: 'user',
},
};
同样,任何嵌套都需要在配置中反映出来。
¥Similarly, any nesting needs to be reflected in the configuration.
How it works
链接通过使用提供的配置将 URL 转换为有效的 导航状态 并反之亦然。例如,路径 /rooms/chat?user=jane
可以转换为如下状态对象:
¥The linking works by translating the URL to a valid navigation state and vice versa using the configuration provided. For example, the path /rooms/chat?user=jane
may be translated to a state object like this:
const state = {
routes: [
{
name: 'rooms',
state: {
routes: [
{
name: 'chat',
params: { user: 'jane' },
},
],
},
},
],
};
例如,你可能希望将路径 /feed/latest
解析为:
¥For example, you might want to parse the path /feed/latest
to something like:
const state = {
routes: [
{
name: 'Chat',
params: {
sort: 'latest',
},
},
];
}
有关状态对象如何构造的更多详细信息,请参阅 导航状态参考。
¥See Navigation State reference for more details on how the state object is structured.
传递参数
¥Passing params
一个常见的用例是将参数传递到屏幕以传递一些数据。例如,你可能希望 Profile
屏幕有一个 id
参数来了解它是哪个用户的个人资料。处理深层链接时,可以通过 URL 将参数传递到屏幕。
¥A common use case is to pass params to a screen to pass some data. For example, you may want the Profile
screen to have an id
param to know which user's profile it is. It's possible to pass params to a screen through a URL when handling deep links.
默认情况下,解析查询参数以获取屏幕的参数。例如,在上面的示例中,URL /user?id=jane
会将 id
参数传递到 Profile
屏幕。
¥By default, query params are parsed to get the params for a screen. For example, with the above example, the URL /user?id=jane
will pass the id
param to the Profile
screen.
你还可以自定义如何从 URL 解析参数。假设你希望 URL 看起来像 /user/jane
,其中 id
参数是 jane
,而不是在查询参数中包含 id
。你可以通过为 path
指定 user/:id
来完成此操作。当路径段以 :
开头时,它将被视为参数。例如,URL /user/jane
将解析为 Profile
屏幕,其中字符串 jane
作为 id
参数的值,并将在 Profile
屏幕中的 route.params.id
中可用。
¥You can also customize how the params are parsed from the URL. Let's say you want the URL to look like /user/jane
where the id
param is jane
instead of having the id
in query params. You can do this by specifying user/:id
for the path
. When the path segment starts with :
, it'll be treated as a param. For example, the URL /user/jane
would resolve to Profile
screen with the string jane
as a value of the id
param and will be available in route.params.id
in Profile
screen.
默认情况下,所有参数都被视为字符串。你还可以自定义如何解析它们,方法是在 parse
属性中指定一个函数来解析参数,并在 stringify
属性中指定一个函数将其转换回字符串。
¥By default, all params are treated as strings. You can also customize how to parse them by specifying a function in the parse
property to parse the param, and a function in the stringify
property to convert it back to a string.
如果你想解析 /user/@jane/settings
以生成参数 { id: 'jane' section: 'settings' }
,你可以使 Profile
的配置如下所示:
¥If you wanted to resolve /user/@jane/settings
to result in the params { id: 'jane' section: 'settings' }
, you could make Profile
's config to look like this:
- Static
- Dynamic
const RootStack = createStackNavigator({
screens: {
Profile: {
screen: ProfileScreen,
linking: {
path: 'user/:id/:section',
parse: {
id: (id) => id.replace(/^@/, ''),
},
stringify: {
id: (id) => `@${id}`,
},
},
},
},
});
const config = {
screens: {
Profile: {
path: 'user/:id/:section',
parse: {
id: (id) => id.replace(/^@/, ''),
},
stringify: {
id: (id) => `@${id}`,
},
},
},
};
Result Navigation State
通过此配置,路径 /user/@jane/settings
将解析为以下状态对象:
¥With this configuration, the path /user/@jane/settings
will resolve to the following state object:
const state = {
routes: [
{
name: 'Profile',
params: { id: 'jane', section: 'settings' },
},
],
};
将参数标记为可选
¥Marking params as optional
有时,根据某些条件,参数可能会或可能不会出现在 URL 中。例如,在上述场景中,你可能并不总是在 URL 中包含部分参数,即 /user/jane/settings
和 /user/jane
都应转到 Profile
屏幕,但 section
参数(在本例中值为 settings
)可能会或可能不会展示。
¥Sometimes a param may or may not be present in the URL depending on certain conditions. For example, in the above scenario, you may not always have the section parameter in the URL, i.e. both /user/jane/settings
and /user/jane
should go to the Profile
screen, but the section
param (with the value settings
in this case) may or may not be present.
在这种情况下,你需要将 section
参数标记为可选。你可以通过在参数名称后添加 ?
后缀来实现:
¥In this case, you would need to mark the section
param as optional. You can do it by adding the ?
suffix after the param name:
- Static
- Dynamic
const RootStack = createStackNavigator({
screens: {
Profile: {
screen: ProfileScreen,
linking: {
path: 'user/:id/:section?',
parse: {
id: (id) => `user-${id}`,
},
stringify: {
id: (id) => id.replace(/^user-/, ''),
},
},
},
},
});
const config = {
screens: {
Profile: {
path: 'user/:id/:section?',
parse: {
id: (id) => `user-${id}`,
},
stringify: {
id: (id) => id.replace(/^user-/, ''),
},
},
},
};
Result Navigation State
通过此配置,路径 /user/jane
将解析为以下状态对象:
¥With this configuration, the path /user/jane
will resolve to the following state object:
const state = {
routes: [
{
name: 'Profile',
params: { id: 'user-jane' },
},
],
};
如果 URL 包含 section
参数(例如 /user/jane/settings
),则将导致具有相同配置的以下内容:
¥If the URL contains a section
param (e.g. /user/jane/settings
), this will result in the following with the same config:
const state = {
routes: [
{
name: 'Profile',
params: { id: 'user-jane', section: 'settings' },
},
],
};
处理不匹配的路由或 404
¥Handling unmatched routes or 404
如果你的应用使用无效 URL 打开,大多数时候你希望显示包含一些信息的错误页面。在网络上,这通常称为 404 - 或页面未找到错误。
¥If your app is opened with an invalid URL, most of the times you'd want to show an error page with some information. On the web, this is commonly known as 404 - or page not found error.
为了解决这个问题,你需要定义一个包罗万象的路由,如果没有其他路由与该路径匹配,则将渲染该路由。你可以通过为路径匹配模式指定 *
来实现:
¥To handle this, you'll need to define a catch-all route that will be rendered if no other routes match the path. You can do it by specifying *
for the path matching pattern:
- Static
- Dynamic
const HomeTabs = createBottomTabNavigator({
screens: {
Feed: {
screen: FeedScreen,
},
Profile: {
screen: HomeScreen,
linking: {
path: 'users/:id',
},
},
Settings: {
screen: SettingsScreen,
linking: {
path: 'settings',
},
},
},
});
const RootStack = createStackNavigator({
screens: {
Home: {
screen: HomeTabs,
},
NotFound: {
screen: NotFoundScreen,
linking: {
path: '*',
},
},
},
});
const config = {
screens: {
Home: {
initialRouteName: 'Feed',
screens: {
Profile: 'users/:id',
Settings: 'settings',
},
},
NotFound: {
path: '*',
},
},
};
在这里,我们定义了一条名为 NotFound
的路由,并将其设置为匹配 *
(即所有内容)。如果路径与 user/:id
或 settings
不匹配,则将通过此路由进行匹配。
¥Here, we have defined a route named NotFound
and set it to match *
aka everything. If the path didn't match user/:id
or settings
, it'll be matched by this route.
Result Navigation State
使用此配置,像 /library
或 /settings/notification
这样的路径将解析为以下状态对象:
¥With this configuration, a path like /library
or /settings/notification
will resolve to the following state object:
const state = {
routes: [{ name: 'NotFound' }],
};
你甚至可以更具体,例如,如果你想为 /settings
下的无效路径显示不同的屏幕,你可以在 Settings
下指定这样的模式:
¥You can even go more specific, for example, say if you want to show a different screen for invalid paths under /settings
, you can specify such a pattern under Settings
:
- Static
- Dynamic
const SettingsStack = createStackNavigator({
screens: {
UserSettings: {
screen: UserSettingsScreen,
linking: {
path: 'user-settings',
},
},
InvalidSettings: {
screen: InvalidSettingsScreen,
linking: {
path: '*',
},
},
},
});
const HomeTabs = createBottomTabNavigator({
screens: {
Feed: {
screen: FeedScreen,
},
Profile: {
screen: HomeScreen,
linking: {
path: 'users/:id',
},
},
Settings: {
screen: SettingsStack,
},
},
});
const RootStack = createStackNavigator({
screens: {
Home: {
screen: HomeTabs,
},
NotFound: {
screen: NotFoundScreen,
linking: {
path: '*',
},
},
},
});
const config = {
screens: {
Home: {
initialRouteName: 'Feed',
screens: {
Profile: 'users/:id',
Settings: {
path: 'settings',
screens: {
InvalidSettings: '*',
},
},
},
},
NotFound: '*',
},
};
Result Navigation State
通过此配置,路径 /settings/notification
将解析为以下状态对象:
¥With this configuration, the path /settings/notification
will resolve to the following state object:
const state = {
routes: [
{
name: 'Home',
state: {
index: 1,
routes: [
{ name: 'Feed' },
{
name: 'Settings',
state: {
routes: [
{ name: 'InvalidSettings', path: '/settings/notification' },
],
},
},
],
},
},
],
};
传递到 NotFound
屏幕的 route
将包含 path
属性,该属性对应于打开页面的路径。如果需要,你可以使用此属性来自定义此屏幕中显示的内容,例如在 WebView
中加载页面:
¥The route
passed to the NotFound
screen will contain a path
property which corresponds to the path that opened the page. If you need, you can use this property to customize what's shown in this screen, e.g. load the page in a WebView
:
function NotFoundScreen({ route }) {
if (route.path) {
return <WebView source={{ uri: `https://mywebsite.com/${route.path}` }} />;
}
return <Text>This screen doesn't exist!</Text>;
}
在进行服务器渲染时,你还希望返回 404 错误的正确状态代码。有关如何处理它的指南,请参阅 服务器渲染文档。
¥When doing server rendering, you'd also want to return correct status code for 404 errors. See server rendering docs for a guide on how to handle it.
渲染初始路由
¥Rendering an initial route
有时你希望确保某个屏幕始终作为导航器状态中的第一个屏幕出现。你可以使用 initialRouteName
属性指定用于初始屏幕的屏幕。
¥Sometimes you want to ensure that a certain screen will always be present as the first screen in the navigator's state. You can use the initialRouteName
property to specify the screen to use for the initial screen.
在上面的示例中,如果你希望 Feed
屏幕成为 Home
下导航器中的初始路由,你的配置将如下所示:
¥In the above example, if you want the Feed
screen to be the initial route in the navigator under Home
, your config will look like this:
- Static
- Dynamic
const HomeTabs = createBottomTabNavigator({
screens: {
Feed: {
screen: FeedScreen,
},
Profile: {
screen: HomeScreen,
linking: {
path: 'users/:id',
},
},
Settings: {
screen: SettingsScreen,
linking: {
path: 'settings',
},
},
},
});
const RootStack = createStackNavigator({
screens: {
Home: {
screen: HomeTabs,
linking: {
initialRouteName: 'Feed',
},
},
NotFound: {
screen: NotFoundScreen,
linking: {
path: '*',
},
},
},
});
const config = {
screens: {
Home: {
initialRouteName: 'Feed',
screens: {
Profile: 'users/:id',
Settings: 'settings',
},
},
},
};
Result Navigation State
通过此配置,路径 /users/42
将解析为以下状态对象:
¥With this configuration, the path /users/42
will resolve to the following state object:
const state = {
routes: [
{
name: 'Home',
state: {
index: 1,
routes: [
{ name: 'Feed' },
{
name: 'Profile',
params: { id: '42' },
},
],
},
},
],
};
initialRouteName
只会将屏幕添加到 React Navigation 的状态。如果你的应用在网络上运行,则浏览器的历史记录将不包含此屏幕,因为用户从未访问过它。因此,如果用户按下浏览器的后退按钮,它不会返回到此屏幕。
¥The initialRouteName
will add the screen to React Navigation's state only. If your app is running on the Web, the browser's history will not contain this screen as the user has never visited it. So, if the user presses the browser's back button, it'll not go back to this screen.
另一件需要记住的事情是,不可能通过 URL 将参数传递到初始屏幕。因此,请确保你的初始路由不需要任何参数或在屏幕配置中指定 initialParams
来传递所需的参数。
¥Another thing to keep in mind is that it's not possible to pass params to the initial screen through the URL. So make sure that your initial route doesn't need any params or specify initialParams
in the screen configuration to pass the required params.
在这种情况下,URL 中的任何参数仅传递到与路径模式 users/:id
匹配的 Profile
屏幕,而 Feed
屏幕不接收任何参数。如果你想在 Feed
屏幕中具有相同的参数,你可以指定 自定义 getStateFromPath
函数 并复制这些参数。
¥In this case, any params in the URL are only passed to the Profile
screen which matches the path pattern users/:id
, and the Feed
screen doesn't receive any params. If you want to have the same params in the Feed
screen, you can specify a custom getStateFromPath
function and copy those params.
同样,如果你想从子屏幕访问父屏幕的参数,你可以使用 React 上下文 来公开它们。
¥Similarly, if you want to access params of a parent screen from a child screen, you can use React Context to expose them.
匹配精确路径
¥Matching exact paths
默认情况下,为每个屏幕定义的路径将与相对于其父屏幕路径的 URL 进行匹配。考虑以下配置:
¥By default, paths defined for each screen are matched against the URL relative to their parent screen's path. Consider the following config:
- Static
- Dynamic
const ProfileTabs = createBottomTabNavigator({
screens: {
Profile: {
screen: HomeScreen,
linking: {
path: 'users/:id',
},
},
},
});
const RootStack = createStackNavigator({
screens: {
Home: {
screen: ProfileTabs,
linking: {
path: 'feed',
},
},
},
});
const config = {
screens: {
Home: {
path: 'feed',
screens: {
Profile: 'users/:id',
},
},
},
};
在这里,你为 Home
屏幕以及子 Profile
屏幕定义了 path
属性。配置文件屏幕指定路径 users/:id
,但由于它嵌套在具有路径 feed
的屏幕内,因此它将尝试匹配模式 feed/users/:id
。
¥Here, you have a path
property defined for the Home
screen, as well as the child Profile
screen. The profile screen specifies the path users/:id
, but since it's nested inside a screen with the path feed
, it'll try to match the pattern feed/users/:id
.
这将导致 URL /feed
导航到 Home
屏幕,/feed/users/cal
导航到 Profile
屏幕。
¥This will result in the URL /feed
navigating to Home
screen, and /feed/users/cal
navigating to the Profile
screen.
在这种情况下,使用 /users/cal
这样的 URL 导航到 Profile
屏幕比使用 /feed/users/cal
更有意义。为此,你可以将相对匹配行为覆盖为 exact
匹配:
¥In this case, it makes more sense to navigate to the Profile
screen using a URL like /users/cal
, rather than /feed/users/cal
. To achieve this, you can override the relative matching behavior to exact
matching:
- Static
- Dynamic
const ProfileTabs = createBottomTabNavigator({
screens: {
Profile: {
screen: HomeScreen,
linking: {
path: 'users/:id',
exact: true,
},
},
},
});
const RootStack = createStackNavigator({
screens: {
Home: {
screen: ProfileTabs,
linking: {
path: 'feed',
},
},
},
});
const config = {
screens: {
Home: {
path: 'feed',
screens: {
Profile: {
path: 'users/:id',
exact: true,
},
},
},
},
};
将 exact
属性设置为 true
时,Profile
将忽略父屏幕的 path
配置,你将能够使用 users/cal
等 URL 导航到 Profile
。
¥With exact
property set to true
, Profile
will ignore the parent screen's path
config and you'll be able to navigate to Profile
using a URL like users/cal
.
从路径中省略屏幕
¥Omitting a screen from path
有时,你可能不希望路径中包含屏幕的路由名称。例如,假设你有一个 Home
屏幕和以下配置。在浏览器中打开页面时,你将获得 /home
作为 URL:
¥Sometimes, you may not want to have the route name of a screen in the path. For example, let's say you have a Home
screen and the following config. When the page is opened in the browser you'll get /home
as the URL:
- Static
- Dynamic
const RootStack = createStackNavigator({
screens: {
Home: {
screen: ProfileScreen,
linking: {
path: 'home',
},
},
Profile: {
screen: HomeScreen,
linking: {
path: 'users/:id',
},
},
},
});
const config = {
screens: {
Home: {
path: 'home',
},
Profile: 'users/:id',
},
};
但如果访问主屏幕时 URL 是 /
就更好了。
¥But it'll be nicer if the URL was just /
when visiting the home screen.
你可以指定一个空字符串作为路径,或者根本不指定路径,React Navigation 不会将屏幕添加到路径中(就像将空字符串添加到路径中一样,这不会改变任何内容):
¥You can specify an empty string as path or not specify a path at all, and React Navigation won't add the screen to the path (think of it like adding empty string to the path, which doesn't change anything):
- Static
- Dynamic
const RootStack = createStackNavigator({
screens: {
Home: {
screen: ProfileScreen,
linking: {
path: '',
},
},
Profile: {
screen: HomeScreen,
linking: {
path: 'users/:id',
},
},
},
});
const config = {
screens: {
Home: {
path: '',
},
Profile: 'users/:id',
},
};
序列化和解析参数
¥Serializing and parsing params
由于 URL 是字符串,因此在构造路径时,路由的任何参数也会转换为字符串。
¥Since URLs are strings, any params you have for routes are also converted to strings when constructing the path.
例如,假设你有一个带有以下配置的 URL /chat/1589842744264
:
¥For example, say you have the URL /chat/1589842744264
with the following config:
- Static
- Dynamic
const RootStack = createStackNavigator({
screens: {
Chat: {
screen: ChatScreen,
linking: {
path: 'chat/:date',
},
},
},
});
const config = {
screens: {
Chat: 'chat/:date',
},
};
处理 URL 时,你的参数将如下所示:
¥When handling the URL, your params will look like this:
{ date: '1589842744264' }
在这里,date
参数被解析为字符串,因为 React Navigation 不知道它应该是时间戳,因此也不知道数字。你可以通过提供用于解析的自定义函数来自定义它:
¥Here, the date
param was parsed as a string because React Navigation doesn't know that it's supposed to be a timestamp, and hence number. You can customize it by providing a custom function to use for parsing:
- Static
- Dynamic
const RootStack = createStackNavigator({
screens: {
Chat: {
screen: ChatScreen,
linking: {
path: 'chat/:date',
parse: {
date: Number,
},
},
},
},
});
const config = {
screens: {
Chat: {
path: 'chat/:date',
parse: {
date: Number,
},
},
},
};
你还可以提供自己的函数来序列化参数。例如,假设你想在路径中使用 DD-MM-YYYY 格式而不是时间戳:
¥You can also provide a your own function to serialize the params. For example, let's say that you want to use a DD-MM-YYYY format in the path instead of a timestamp:
- Static
- Dynamic
const RootStack = createStackNavigator({
screens: {
Chat: {
screen: ChatScreen,
linking: {
path: 'chat/:date',
parse: {
date: (date) => new Date(date).getTime(),
},
stringify: {
date: (date) => {
const d = new Date(date);
return d.getFullYear() + '-' + d.getMonth() + '-' + d.getDate();
},
},
},
},
},
});
const config = {
screens: {
Chat: {
path: 'chat/:date',
parse: {
date: (date) => new Date(date).getTime(),
},
stringify: {
date: (date) => {
const d = new Date(date);
return d.getFullYear() + '-' + d.getMonth() + '-' + d.getDate();
},
},
},
},
};
根据你的要求,你可以使用此功能来解析和字符串化更复杂的数据。
¥Depending on your requirements, you can use this functionality to parse and stringify more complex data.
高级案例
¥Advanced cases
对于某些高级情况,指定映射可能还不够。为了处理这种情况,你可以指定一个自定义函数将 URL 解析为状态对象 (getStateFromPath
),并指定一个自定义函数将状态对象序列化为 URL (getPathFromState
)。
¥For some advanced cases, specifying the mapping may not be sufficient. To handle such cases, you can specify a custom function to parse the URL into a state object (getStateFromPath
), and a custom function to serialize the state object into an URL (getPathFromState
).
示例:
¥Example:
const linking = {
prefixes: ['https://mychat.com', 'mychat://'],
getStateFromPath: (path, options) => {
// Return a state object here
// You can also reuse the default logic by importing `getStateFromPath` from `@react-navigation/native`
},
getPathFromState(state, config) {
// Return a path string here
// You can also reuse the default logic by importing `getPathFromState` from `@react-navigation/native`
},
// ...
};
在线运行
¥Playground
- Static
- Dynamic
Playground 不适用于静态配置。
¥Playground is not available for static config.
你可以尝试自定义下面的配置和路径,并查看如何解析路径。
¥You can play around with customizing the config and path below, and see how the path is parsed.
id | : | "vergil" |