信息披露

一个简单、可访问的构建自定义 UI 的基础,用于显示和隐藏内容,例如可切换的手风琴面板。

要开始使用,请通过 npm 安装 Headless UI。

请注意,此库仅支持 Vue 3

npm install @headlessui/vue

信息披露是使用 DisclosureDisclosureButtonDisclosurePanel 组件构建的。

按钮将自动在单击时打开/关闭面板,所有组件都将接收适当的 aria-* 相关属性,如 aria-expandedaria-controls

<template> <Disclosure> <DisclosureButton class="py-2"> Is team pricing available? </DisclosureButton> <DisclosurePanel class="text-gray-500"> Yes! You can purchase a license that you can share with your entire team. </DisclosurePanel> </Disclosure> </template> <script setup> import { Disclosure, DisclosureButton, DisclosurePanel, } from '@headlessui/vue' </script>

Headless UI 跟踪每个组件的大量状态,例如当前选定的列表框选项、弹出窗口是打开还是关闭,或者通过键盘当前激活的信息披露中的哪个项目。

但由于组件是无头且默认情况下完全没有样式的,因此您无法看到 UI 中的这些信息,直到您自己为每个状态提供所需的样式。

每个组件都通过 插槽道具 公开其当前状态的信息,您可以使用这些信息有条件地应用不同的样式或渲染不同的内容。

例如,Disclosure 组件公开了一个 open 状态,它告诉您信息披露当前是否处于打开状态。

<template>
<Disclosure v-slot="{ open }">
<!-- Use the `open` state to conditionally change the direction of an icon. --> <DisclosureButton class="py-2"> <span>Do you offer technical support?</span>
<ChevronRightIcon :class="open && 'rotate-90 transform'" />
</DisclosureButton> <DisclosurePanel>No</DisclosurePanel> </Disclosure> </template> <script setup> import { Disclosure, DisclosureButton, DisclosurePanel, } from '@headlessui/vue' import { ChevronRightIcon } from '@heroicons/vue/20/solid' </script>

有关所有可用插槽道具的完整列表,请参阅 组件 API 文档

每个组件还通过一个 data-headlessui-state 属性公开其当前状态的信息,您可以使用它有条件地应用不同的样式。

插槽道具 API 中的任何状态为 true 时,它们将作为空格分隔的字符串列在这个属性中,因此您可以使用 CSS 属性选择器[attr~=value] 的形式来定位它们。

例如,以下是如何在信息披露打开时渲染 Disclosure 组件

<!-- Rendered `Disclosure` --> <div data-headlessui-state="open"> <button data-headlessui-state="open">Do you offer technical support?</button> <div data-headlessui-state="open">No</div> </div>

如果您正在使用 Tailwind CSS,您可以使用 @headlessui/tailwindcss 插件使用 ui-open:* 等修饰符来定位此属性

<template> <Disclosure> <DisclosureButton class="py-2"> <span>Do you offer technical support?</span>
<ChevronRightIcon class="ui-open:rotate-90 ui-open:transform" />
</DisclosureButton> <DisclosurePanel>No</DisclosurePanel> </Disclosure> </template> <script setup> import { Disclosure, DisclosureButton, DisclosurePanel, } from '@headlessui/vue' import { ChevronRightIcon } from '@heroicons/vue/20/solid' </script>

默认情况下,您的 DisclosurePanel 将根据 Disclosure 组件本身内部跟踪的内部打开状态自动显示/隐藏。

<template> <Disclosure> <DisclosureButton>Is team pricing available?</DisclosureButton> <!-- By default, the `DisclosurePanel` will automatically show/hide when the `DisclosureButton` is pressed. --> <DisclosurePanel> Yes! You can purchase a license that you can share with your entire team. </DisclosurePanel> </Disclosure> </template> <script setup> import { Disclosure, DisclosureButton, DisclosurePanel, } from '@headlessui/vue' </script>

如果您想自己处理它(也许是因为您需要出于某种原因添加额外的包装元素),您可以将 static 道具传递给 DisclosurePanel 以告诉它始终渲染,然后使用 open 插槽道具来控制面板何时自己显示/隐藏。

<template>
<Disclosure v-slot="{ open }">
<DisclosureButton>Is team pricing available?</DisclosureButton>
<div v-show="open">
<!-- Using the `static` prop, the `DisclosurePanel` is always rendered and the `open` state is ignored. -->
<DisclosurePanel static>
Yes! You can purchase a license that you can share with your entire team. </DisclosurePanel> </div> </Disclosure> </template> <script setup> import { Disclosure, DisclosureButton, DisclosurePanel, } from '@headlessui/vue' </script>

要手动关闭单击其面板子项的信息披露,请将该子项渲染为 DisclosureButton。您可以使用 :as 道具自定义要渲染的元素。

<template> <Disclosure> <DisclosureButton>Open mobile menu</DisclosureButton> <DisclosurePanel>
<DisclosureButton :as="MyLink" href="/home">Home</DisclosureButton>
<!-- ... --> </DisclosurePanel> </Disclosure> </template> <script setup> import { Disclosure, DisclosureButton, DisclosurePanel, } from '@headlessui/vue' import MyLink from './MyLink' </script>

这在将信息披露用于移动菜单等包含链接的内容时特别有用,在这些链接中,您希望在导航到下一页时关闭信息披露。

或者,DisclosureDisclosurePanel 公开了一个 close() 插槽道具,您可以使用它以命令式方式关闭面板,例如在运行异步操作后。

<template> <Disclosure> <DisclosureButton>Terms</DisclosureButton>
<DisclosurePanel v-slot="{ close }">
<button @click="accept(close)">Read and accept</button>
</DisclosurePanel>
</Disclosure> </template> <script setup> import { Disclosure, DisclosureButton, DisclosurePanel, } from '@headlessui/vue'
async function accept(close) {
await fetch('/accept-terms', { method: 'POST' })
close()
}
</script>

默认情况下,DisclosureButton 在调用 close() 后会获得焦点,但您可以通过将 ref 传递到 close(ref) 中来更改它。

要动画化信息披露面板的打开/关闭,您可以使用 Vue 的内置 <transition> 组件。您所要做的就是将您的 DisclosurePanel 包装在一个 <transition> 中,过渡将自动应用。

<template> <Disclosure> <DisclosureButton>Is team pricing available?</DisclosureButton> <!-- Use the built-in `transition` component to add transitions. -->
<transition
enter-active-class="transition duration-100 ease-out"
enter-from-class="transform scale-95 opacity-0"
enter-to-class="transform scale-100 opacity-100"
leave-active-class="transition duration-75 ease-out"
leave-from-class="transform scale-100 opacity-100"
leave-to-class="transform scale-95 opacity-0"
>
<DisclosurePanel> Yes! You can purchase a license that you can share with your entire team. </DisclosurePanel> </transition> </Disclosure> </template> <script setup> import { Disclosure, DisclosureButton, DisclosurePanel, } from '@headlessui/vue' </script>

如果您想为信息披露的不同子项协调多个过渡,请查看 Headless UI 中包含的过渡组件

Disclosure 及其子组件分别渲染一个对该组件而言合理的默认元素:Button 渲染一个 <button>Panel 渲染一个 <div>。相反,根 Disclosure 组件不渲染元素,而是默认情况下直接渲染其子组件。

这很容易使用 as 道具更改,它存在于每个组件上。

<template> <!-- Render a `div` for the root `Disclosure` component -->
<Disclosure as="div">
<!-- Don't render any element (only children) for the `DisclosureButton` component -->
<DisclosureButton as="template">
<button>What languages do you support?</button> </DisclosureButton> <!-- Render a `ul` for the `DisclosurePanel` component -->
<DisclosurePanel as="ul">
<li>HTML</li> <li>CSS</li> <li>JavaScript</li> </DisclosurePanel> </Disclosure> </template> <script setup> import { Disclosure, DisclosureButton, DisclosurePanel, } from '@headlessui/vue' </script>

单击 DisclosureButton 会切换信息披露面板的打开和关闭。

命令描述

EnterSpaceDisclosureButton 获得焦点时。

切换面板

所有相关的 ARIA 属性都会自动管理。

主要的信息披露组件。

道具默认值描述
as模板
字符串 | 组件

Disclosure 应该渲染的元素或组件。

defaultOpenfalse
布尔值

Disclosure 组件是否应该默认打开。

插槽道具描述
open

布尔值

信息披露是否处于打开状态。

close

(ref?: ref | HTMLElement) => void

关闭信息披露并重新聚焦 DisclosureButton。可以选择传递一个refHTMLElement 来改为聚焦该元素。

触发组件,用于切换信息披露。

道具默认值描述
as按钮
字符串 | 组件

DisclosureButton 应该渲染的元素或组件。

插槽道具描述
open

布尔值

信息披露是否处于打开状态。

此组件包含信息披露的内容。

道具默认值描述
asdiv
字符串 | 组件

DisclosurePanel 应该渲染的元素或组件。

staticfalse
布尔值

元素是否应该忽略内部管理的打开/关闭状态。

注意:staticunmount 不能同时使用。如果您尝试这样做,您将收到一个 TypeScript 错误。

unmounttrue
布尔值

元素是否应该根据打开/关闭状态卸载或隐藏。

注意:staticunmount 不能同时使用。如果您尝试这样做,您将收到一个 TypeScript 错误。

插槽道具描述
open

布尔值

信息披露是否处于打开状态。

close

(ref?: ref | HTMLElement) => void

关闭信息披露并重新聚焦 DisclosureButton。可以选择传递一个refHTMLElement 来改为聚焦该元素。

如果您对使用 Headless UI 和 Tailwind CSS 的预设计组件示例感兴趣,请查看 Tailwind UI - 我们构建的一系列精美设计和精心制作的组件。

这是支持我们对像这样的开源项目的工作的好方法,并且使我们能够改进它们并保持良好维护。