链接预览
了解如何在使用 Expo Router 时在 iOS 上为链接添加预览。
重要 链接预览是仅在 iOS 上可用的功能,适用于 SDK 54 及更高版本。
链接预览(也称为“Peek and Pop”)是 iOS 上常用的一个功能,用于向用户显示链接的屏幕预览弹窗。 本指南将向你展示如何在 iOS 上为你的应用添加和自定义链接预览。
🌐 Link preview (also known as "Peek and Pop") is a feature commonly used on iOS to show users a preview popup of the screen for a link. This guide will show you how to add and customize a link preview for your app on iOS.
如果你的应用中有链接,你可以通过将链接的内容替换为 Link.Trigger 并向其添加 Link.Preview 组件来为其添加链接预览。这将创建一个链接所指向页面的预览。
🌐 If you have a link in your app, you can add a link preview to it by replacing the link's content with a Link.Trigger and adding the Link.Preview component to it. This will create a preview of the page that the link points to.
import { Link } from 'expo-router'; export default function Page() { return ( <Link href="/about"> <Link.Trigger>About</Link.Trigger> <Link.Preview /> </Link> ); }
自定义链接预览
🌐 Customizing the link preview
默认情况下,链接预览会呈现为全尺寸页面快照。有几种方法可以自定义这种行为。
🌐 By default, the link preview is rendered as a full-sized page snapshot. There are several ways to customize this behavior.
自定义大小
🌐 Custom size
你可以使用 width 和 height 来建议首选的预览尺寸。系统会考虑这些偏好,但可能会根据可用空间或平台行为进行调整。
🌐 You can use width and height to suggest a preferred preview size. The system will consider these preferences but may override them based on available space or platform behavior.
<Link href="..."> <Link.Trigger>Content</Link.Trigger> <Link.Preview style={{ width: 300, height: 200 }} /> </Link>
以下示例展示了 iOS 上的自定义链接预览大小:
🌐 The following example shows a custom link preview size on iOS:
自定义预览
🌐 Custom preview
如果你不想显示默认预览,你可以通过子元素向 Link.Preview 组件传递自定义内容。这个自定义内容将替代链接目标的默认预览。
🌐 If you don't want to show the default preview, you can pass custom content to the Link.Preview component via children. This custom content will replace the default preview of the link target.
export default function Page() { const [imageSize, setImageSize] = useState({ width: 0, height: 0 }); const { width } = useWindowDimensions(); const previewHeight = (width / imageSize.width) * imageSize.height; return ( <Link href="/about"> <Link.Trigger>About</Link.Trigger> <Link.Trigger>Content</Link.Trigger> <Link.Preview style={{ width, height: previewHeight }}> <Image onLoad={e => setImageSize(e.nativeEvent.source)} source={source} style={{ width: '100%', height: '100%' }} /> </Link.Preview> </Link> ); }
以下示例展示了 iOS 上的自定义链接预览:
🌐 The following example shows a custom link preview on iOS:
菜单
🌐 Menu
要在预览旁边显示上下文菜单,请添加一个具有 Link.MenuAction 子项的 Link.Menu。
🌐 To render a context menu next to the preview, add a Link.Menu with Link.MenuAction children.
<Link href="/about"> <Link.Trigger>About</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> </Link>
以下示例展示了 iOS 上的自定义链接预览:
🌐 The following example shows a custom link preview on iOS:
图标
🌐 Icons
你可以使用 SF Symbols 为每个菜单操作指定图标。
🌐 You can specify an icon for each menu action using SF Symbols.
<Link href="/about"> <Link.Trigger>About</Link.Trigger> <Link.Menu> <Link.MenuAction title="Share" icon="square.and.arrow.up" onPress={handleSharePress} /> <Link.MenuAction title="Block" icon="nosign" onPress={handleBlockPress} /> <Link.MenuAction title="Follow" icon="person.crop.circle.badge.plus" onPress={handleFollowPress} /> <Link.MenuAction title="Copy" icon="doc.on.doc" onPress={handleCopyPress} /> </Link.Menu> </Link>
以下示例展示了一个包含四个元素的上下文菜单,每个元素在 iOS 上使用不同的图标:
🌐 The following example shows a context menu with four elements, each using a different icon on iOS:
嵌套菜单
🌐 Nested menus
你可以通过将 Link.Menu 放在另一个菜单中来嵌套菜单:
🌐 You can nest menus by placing a Link.Menu inside another menu:
<Link href="..."> <Link.Trigger>About</Link.Trigger> <Link.Menu> <Link.MenuAction title="Share" icon="square.and.arrow.up" onPress={() => {}} /> <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>
以下示例展示了 iOS 上的嵌套上下文菜单:
🌐 The following example shows a nested context menu on iOS:
更多自定义选项
🌐 More customization options
要探索所有可用的自定义选项,请参阅 Link.MenuAction 的 API 文档。
🌐 To explore all available customization options, see the API documentation for Link.MenuAction.
检测组件是否处于预览状态
🌐 Detecting if component is in preview
如果你正在构建一个可能在预览中渲染的组件,你可以使用 useIsPreview() 钩子来相应地调整其行为:
🌐 If you're building a component that might be rendered inside a preview, you can use the useIsPreview() hook to adjust its behavior accordingly:
function MyComponent() { // This will be true if component/screen is being rendered inside a preview const isInsidePreview = useIsPreview(); return isInsidePreview ? <Text>From within preview</Text> : <Text>I am outside of preview</Text>; }
已知的限制
🌐 Known limitations
replace 不支持
🌐 replace not supported
在 replace 模式下使用链接预览目前不受支持。预览只能在默认的 push 导航模式下使用。
🌐 Using link previews with replace mode is currently not supported. Previews can only be used with the default push navigation mode.
JavaScript 标签页和插槽
🌐 JavaScript tabs and slots
在 JavaScript 标签(而非原生标签)或 Slot 内导航时,预览过渡动画可能显得卡顿。这是因为 React 的渲染有延迟,而原生预览动画会立即开始。为避免此问题,请使用原生标签和堆栈导航器。
🌐 When navigating within JavaScript tabs (rather than native tabs) or Slot, preview transition animations may appear clunky. This is due to React's delayed rendering while the native preview animation begins immediately. To prevent this issues use, native tabs and stack navigators.
缺少 Link.Trigger
🌐 Missing Link.Trigger
如果你在没有 Link.Trigger 的情况下使用预览或上下文菜单渲染 Link,将会抛出异常。同样,如果在使用预览模式时将任何非 Link.* 组件直接放入 Link 中,也会发生同样的情况。
🌐 If you render a Link with a preview or context menu, but without a Link.Trigger, an exception will be thrown. The same applies if you place any non-Link.* component directly inside Link when using preview mode.
具有 asChild 属性的多个 Link.Trigger 子组件
🌐 Multiple Link.Trigger children with asChild prop
在将 Link 与 asChild 一起使用时,你只能为 Link.Trigger 指定 一个 子元素。onPress 事件将仅转发给该子元素。
🌐 When using Link with asChild, you may only specify one child for Link.Trigger. The onPress event will be forwarded to that child only.
预览打开时更改 href
🌐 Changing href while preview is open
在预览打开时动态更改 href 属性的路径 不支持。你只能动态修改查询参数。
🌐 Changing href prop's path dynamically while the preview is open is not supported. You may only modify the query parameters dynamically.