backdrop
组件

Splitter

一种将布局分割为可调整大小区域的组件。
Panel A
Panel B
Panel C

特性

  • 支持键盘交互。
  • 支持水平/垂直布局。
  • 支持嵌套布局。
  • 支持从右到左方向。
  • 可跨另一面板调整大小。
  • 可条件化挂载。

安装

通过命令行安装该组件。

sh
$ npm add reka-ui

结构

导入所有部件并组合在一起。

vue
<script setup>
import { SplitterGroup, SplitterPanel, SplitterResizeHandle } from 'reka-ui'
</script>

<template>
  <SplitterGroup>
    <SplitterPanel />
    <SplitterResizeHandle />
  </SplitterGroup>
</template>

API 参考

Group

包含 Splitter 的所有部件。

PropDefaultType
as
'div'
AsTag | Component

The element or component this component should render as. Can be overwritten by asChild.

asChild
boolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

autoSaveId
null
string | null

Unique id used to auto-save group arrangement via localStorage.

direction*
'vertical' | 'horizontal'

The group orientation of splitter.

id
string | null

Group id; falls back to useId when not provided.

keyboardResizeBy
10
number | null

Step size when arrow key was pressed.

storage
defaultStorage
PanelGroupStorage

Custom storage API; defaults to localStorage

EmitPayload
layout
[val: number[]]

Event handler called when group layout changes

Slots (default)Payload
layout
number[]

Current size of layout

Data AttributeValue
[data-orientation]"vertical" | "horizontal"
[data-state]"collapsed" | "expanded" | "可折叠时存在"

Panel

可折叠的区域。

PropDefaultType
as
'div'
AsTag | Component

The element or component this component should render as. Can be overwritten by asChild.

asChild
boolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

collapsedSize
number

The size of panel when it is collapsed.

collapsible
boolean

Should panel collapse when resized beyond its minSize. When true, it will be collapsed to collapsedSize.

defaultSize
number

Initial size of panel (numeric value between 1-100)

id
string

Panel id (unique within group); falls back to useId when not provided

maxSize
number

The maximum allowable size of panel (numeric value between 1-100); defaults to 100

minSize
number

The minimum allowable size of panel (numeric value between 1-100); defaults to 10

order
number

The order of panel within group; required for groups with conditionally rendered panels

EmitPayload
collapse
[]

Event handler called when panel is collapsed.

expand
[]

Event handler called when panel is expanded.

resize
[size: number, prevSize: number]

Event handler called when panel is resized; size parameter is a numeric value between 1-100.

Slots (default)Payload
isCollapsed
boolean

Is the panel collapsed

isExpanded
boolean

Is the panel expanded

collapse
(): void

If panel is collapsible, collapse it fully.

expand
(): void

If panel is currently collapsed, expand it to its most recent size.

resize
(size: number): void

Resize panel to the specified percentage (1 - 100).

MethodsType
collapse
() => void

If panel is collapsible, collapse it fully.

expand
() => void

If panel is currently collapsed, expand it to its most recent size.

getSize
() => number

Gets the current size of the panel as a percentage (1 - 100).

resize
(size: number) => void

Resize panel to the specified percentage (1 - 100).

Resize Handle

用于调整大小的手柄。

PropDefaultType
as
'div'
AsTag | Component

The element or component this component should render as. Can be overwritten by asChild.

asChild
boolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

disabled
boolean

Disable drag handle

hitAreaMargins
PointerHitAreaMargins

Allow this much margin when determining resizable handle hit detection

id
string

Resize handle id (unique within group); falls back to useId when not provided

nonce
string

Will add nonce attribute to the style tag which can be used by Content Security Policy.
If omitted, inherits globally from ConfigProvider.

tabindex
0
number

Tabindex for the handle

EmitPayload
dragging
[isDragging: boolean]

Event handler called when dragging the handler.

Data AttributeValue
[data-state]"drag" | "hover" | "inactive"
[data-disabled]禁用时存在
[data-orientation]"vertical" | "horizontal"

示例

可折叠

使用 collapsible 属性,允许面板在达到 minSize 时折叠至 collapsedSize

(需要 collapsedSizeminSize 属性。)

vue
<template>
  <SplitterGroup>
    <SplitterPanel
      collapsible
      :collapsed-size="10"
      :min-size="35"
    >
      Panel A
    </SplitterPanel>
    <SplitterResizeHandle />
    <SplitterPanel>
      Panel B
    </SplitterPanel>
  </SplitterGroup>
</template>

持久化到 localStorage

使用 autoSaveId 属性将布局数据保存到 localStorage

vue
<template>
  <SplitterGroup auto-save-id="any-id">

  </SplitterGroup>
</template>

SSR 下的布局持久化

默认情况下,Splitter 使用 localStorage 来持久化布局。在服务器渲染时,当默认布局(在服务器上渲染)被持久化布局(在 localStorage 中)替换时,可能会导致闪烁。避免这种闪烁的方法是同时使用 cookie 来持久化布局,如下所示:

vue
<!-- 使用 Nuxt -->
<script setup lang="ts">
const layout = useCookie<number[]>('splitter:layout')
</script>

<template>
  <SplitterGroup
    direction="horizontal"
    @layout="layout = $event"
  >
    <SplitterPanel :default-size="layout[0]">

    </SplitterPanel>
    <SplitterResizeHandle />
    <SplitterPanel :default-size="layout[1]">

    </SplitterPanel>
  </SplitterGroup>
</template>

以编程方式折叠/展开

有时面板需要响应用户操作来调整大小或折叠/展开。SplitterPanel 提供了 collapseexpand 方法来实现这一点。

vue
<script setup lang="ts">
const panelRef = ref<InstanceType<typeof SplitterPanel>>()
</script>

<template>
  <button
    @click="panelRef?.isCollapsed ? panelRef?.expand() : panelRef?.collapse() "
  >
    {{ panelRef?.isCollapsed ? 'Expand' : 'Collapse' }}
  </button>

  <SplitterGroup>
    <SplitterPanel
      ref="panelRef"
      collapsible
      :collapsed-size="10"
      :min-size="35"
    >

    </SplitterPanel>
    <SplitterResizeHandle />
    <SplitterPanel>

    </SplitterPanel>
  </SplitterGroup>
</template>

自定义手柄

通过传递任意元素作为插槽来自定义手柄。

vue
<template>
  <SplitterGroup>
    <SplitterPanel>

    </SplitterPanel>
    <SplitterResizeHandle>
      <Icon icon="radix-icons-drag-handle-dots-2" />
    </SplitterResizeHandle>
    <SplitterPanel>

    </SplitterPanel>
  </SplitterGroup>
</template>

SSR

Splitter 组件严重依赖唯一的 id,然而对于 Vue<3.4,我们没有可靠的方法来生成 SSR友好的 id

因此,如果您使用 Nuxt 或其他 SSR 框架,您需要手动为所有 Splitter 组件添加 id。或者,您可以将组件用 <ClientOnly> 包装。

vue
<template>
  <SplitterGroup id="group-1">
    <SplitterPanel id="group-1-panel-1">

    </SplitterPanel>
    <SplitterResizeHandle id="group-1-resize-1">
      <Icon icon="radix-icons-drag-handle-dots-2" />
    </SplitterResizeHandle>
    <SplitterPanel id="group-1-panel-2">

    </SplitterPanel>
  </SplitterGroup>
</template>

可访问性

遵循窗口分割器 WAI-ARIA 设计模式

键盘交互

KeyDescription
Enter
如果主窗格未折叠,则折叠该窗格。如果窗格已折叠,则将分割器恢复到其先前位置。
ArrowDown
将水平分割器向下移动。
ArrowUp
将水平分割器向上移动。
ArrowRight
将垂直分割器向右移动。
ArrowLeft
将垂直分割器向左移动。
Home
将分割器移动到使主窗格具有其最小允许尺寸的位置。
End
将分割器移动到使主窗格具有其最大允许尺寸的位置。