弹出窗口是一种交互式迷你对话框浮动元素,当单击该元素时,它会显示与锚元素相关的信息。
¥A popover is an interactive mini-dialog floating element that displays information related to an anchor element when the element is clicked.
基础
¥Essentials
可访问的弹出窗口组件具有以下品质:
¥An accessible popover component has the following qualities:
-
动态锚定位:弹出窗口位于其参考元素旁边,保持锚定到它,同时避免冲突。
¥Dynamic anchor positioning: The popover is positioned next to its reference element, remaining anchored to it while avoiding collisions.
-
事件:单击参考元素时,它会打开或关闭弹出窗口。
¥Events: When the reference element is clicked, it toggles the popover open or closed.
-
退出:当用户在弹出窗口打开时按下
esc
键或在弹出窗口外部时,它将关闭。¥Dismissal: When the user presses the
esc
key or outside the popover while it is open, it closes. -
角色:这些元素被赋予了相关的角色和 ARIA 属性,以便屏幕阅读器可以访问。
¥Role: The elements are given relevant role and ARIA attributes to be accessible to screen readers.
-
焦点管理:焦点针对非模态或模态行为进行管理。
¥Focus management: Focus is managed for non-modal or modal behavior.
示例
¥Examples
下面有部分对这两个示例进行了深入解释。
¥Both of these examples have sections explaining them in-depth below.
基本弹出窗口
¥Basic popover
此示例演示如何创建在单个实例中使用的弹出窗口以熟悉基础知识。
¥This example demonstrates how to create a popover for use in a single instance to familiarize yourself with the fundamentals.
让我们看一下这个例子:
¥Let’s walk through the example:
打开状态
¥Open state
isOpen
确定弹出窗口当前是否在屏幕上打开。它用于条件渲染。
¥isOpen
determines whether or not the popover is
currently open on the screen. It is used for conditional
rendering.
useFloating 钩子
¥useFloating Hook
useFloating()
Hook 为我们的弹出窗口提供定位和上下文。我们需要向它传递一些信息:
¥The useFloating()
Hook provides positioning and context
for our popover. We need to pass it some information:
-
open
:上面useState()
Hook 的打开状态。¥
open
: The open state from ouruseState()
Hook above. -
onOpenChange
:打开或关闭弹出窗口时将调用的回调函数。我们将使用它来更新我们的isOpen
状态。¥
onOpenChange
: A callback function that will be called when the popover is opened or closed. We’ll use this to update ourisOpen
state. -
middleware
:导入中间件并将其传递到数组,以确保弹出窗口保留在屏幕上,无论它最终位于何处。¥
middleware
: Import and pass middleware to the array that ensure the popover remains on the screen, no matter where it ends up being positioned. -
whileElementsMounted
:仅当参考元素和浮动元素都已安装以提高性能时,才可以在必要时更新位置,确保弹出框保持锚定到参考元素。¥
whileElementsMounted
: Ensure the popover remains anchored to the reference element by updating the position when necessary, only while both the reference and floating elements are mounted for performance.
与钩子交互
¥Interaction Hooks
交互钩子返回包含属性键的对象,这些属性使弹出窗口能够打开、关闭或可供屏幕阅读器访问。
¥Interaction Hooks return objects containing keys of props that enable the popover to be opened, closed, or accessible to screen readers.
使用从 Hook 返回的 context
,调用交互 Hooks:
¥Using the context
that was returned from the Hook,
call the interaction Hooks:
-
useClick()
添加了单击参考元素时打开或关闭弹出窗口的功能。¥
useClick()
adds the ability to toggle the popover open or closed when the reference element is clicked. -
useDismiss()
添加了当用户按esc
键或按弹出窗口外部时关闭弹出窗口的功能。¥
useDismiss()
adds the ability to dismiss the popover when the user presses theesc
key or presses outside of the popover. -
useRole()
将dialog
的正确 ARIA 属性添加到弹出窗口和引用元素中。¥
useRole()
adds the correct ARIA attributes for adialog
to the popover and reference elements.
最后,useInteractions()
将他们所有的 props 合并为可用于渲染的 prop getter。
¥Finally, useInteractions()
merges all of their props into
prop getters which can be used for rendering.
渲染
¥Rendering
现在我们已经设置了所有变量和 Hooks,我们可以渲染我们的元素。
¥Now we have all the variables and Hooks set up, we can render out our elements.
-
{...getReferenceProps()}
/{...getFloatingProps()}
将交互 Hook 中的 props 传播到相关元素上。它们包含onClick
、aria-expanded
等属性。¥
{...getReferenceProps()}
/{...getFloatingProps()}
spreads the props from the interaction Hooks onto the relevant elements. They contain props likeonClick
,aria-expanded
, etc. -
<FloatingFocusManager />
是一个管理非模态或模态行为弹出窗口焦点的组件。它应该直接封装浮动元素,并且仅在弹出框也被渲染时才被渲染。FloatingFocusManager
文档。¥
<FloatingFocusManager />
is a component that manages focus of the popover for non-modal or modal behavior. It should directly wrap the floating element and only be rendered when the popover is also rendered.FloatingFocusManager
docs.
模态和非模态行为
¥Modal and non-modal behavior
在上面的示例中,我们使用了非模态焦点管理,但是弹出窗口的焦点管理行为可以是模态的,也可以是非模态的。它们的区别如下:
¥In the above example we used non-modal focus management, but the focus management behavior of a popover can be either modal or non-modal. They are differentiated as follows:
Modal
-
弹出窗口及其内容是唯一可以获得焦点的元素。当弹出窗口打开时,用户无法与页面的其余部分(也不能屏幕阅读器)交互,直到弹出窗口关闭。
¥The popover and its contents are the only elements that can receive focus. When the popover is open, the user cannot interact with the rest of the page (nor can screen readers) until the popover is closed.
-
需要一个明确的关闭按钮(不过,它可以在视觉上隐藏)。
¥Needs an explicit close button (though, it can be visually hidden).
此行为是默认行为:
¥This behavior is the default:
非模态
¥Non-modal
-
弹出窗口及其内容可以接收焦点,但用户仍然可以与页面的其余部分进行交互。
¥The popover and its contents can receive focus, but the user can still interact with the rest of the page too.
-
当在弹出窗口之外进行 Tab 键切换时,弹出窗口会在失去焦点时自动关闭,并且自然 DOM 顺序中的下一个可聚焦元素将获得焦点。
¥When tabbing outside of it, the popover automatically closes when it loses focus and the next focusable element in the natural DOM order receives focus.
-
不需要明确的关闭按钮。
¥Does not need an explicit close button.
可以使用 modal
属性配置此行为,如下所示:
¥This behavior can be configured with the modal
prop
like so:
可重复使用的弹出组件
¥Reusable popover component
最好创建一个可重用的组件 API,可以更轻松地在各种不同的场景中使用。我们可以将所有 Hook 放入单个自定义 Hook 中,以获得更好的可重用性,然后由封装状态的控制器组件使用。
¥It is better to create a reusable component API that can be used in a variety of different scenarios more easily. We can place all of our Hooks into a single custom Hook for better reusability, which is then used by a controller component which encapsulates the state.
可重复使用的组件可以:
¥The reusable component can:
-
不受控制或受控制
¥Be uncontrolled or controlled
-
接受任何元素作为
<PopoverTrigger />
¥Accept any element as the
<PopoverTrigger />
-
读取打开状态改变样式
¥Read the open state to change styles
控制器组件
¥Controller component
<Popover />
这是控制器组件,用于管理弹出窗口的状态并向其余组件提供 API。
¥This is the controller component that manages the popover’s state and provides the API to the rest of the components.
渲染组件
¥Render components
这些组件读取根 Popover 组件提供的上下文并渲染适当的元素。
¥These components read the context provided by the root Popover component and render the appropriate elements.
组件必须封装在 forwardRef()
中以允许引用,并且应该合并引用以确保所有引用都被保留并转发到元素。属性也被合并以防止覆盖。
¥The components must be wrapped in forwardRef()
to allow
refs, and should merge the refs to ensure all refs are preserved
and forwarded to the element. Props are also merged to prevent
overwriting.
-
<PopoverTrigger />
是弹出框所连接的触发按钮。如果你想将asChild
属性附加到自定义元素,则它接受asChild
属性。它还具有基于打开/关闭状态附加到样式的data-state
。¥
<PopoverTrigger />
is the trigger button the popover is attached to. This accepts anasChild
prop if you want to attach it to a custom element. It also has adata-state
attached to style based on the open/closed state. -
<PopoverContent />
是弹出框元素,它可以包含任何子元素(React 节点)。¥
<PopoverContent />
is the popover element, which can contain any children (React nodes). -
<PopoverHeading />
(可选)是弹出窗口的标题元素。¥
<PopoverHeading />
(optional) is the heading element for the popover. -
<PopoverDescription />
(可选)是弹出窗口的描述元素。¥
<PopoverDescription />
(optional) is the description element for the popover. -
<PopoverClose />
(可选)是使用模式焦点管理时弹出窗口的关闭按钮。¥
<PopoverClose />
(optional) is the close button for the popover when using modal focus management.