Splitter 分栏

可以拖动分隔线调整比例的分栏容器。

目录

第 I 章

第 II 章

第 III 章

正文

拖动中间的分隔线可以调整两侧的宽度。

import { Card, Splitter, SplitterHandle, SplitterPanel, Stack, Text } from '@hina-ui/react'

const chapters = ['第 I 章', '第 II 章', '第 III 章']

export default function Demo() {
  return (
    <Card padded={false} className="w-full max-w-2xl overflow-hidden">
      <Splitter className="h-64">
        <SplitterPanel defaultSize={32} minSize={20}>
          <Stack gap="xs" className="p-4">
            <Text size="sm" tone="faint">
              目录
            </Text>
            {chapters.map(chapter => (
              <Text key={chapter} size="sm">
                {chapter}
              </Text>
            ))}
          </Stack>
        </SplitterPanel>
        <SplitterHandle />
        <SplitterPanel defaultSize={68}>
          <Stack gap="sm" className="p-4">
            <Text size="sm" tone="faint">
              正文
            </Text>
            <Text size="sm">拖动中间的分隔线可以调整两侧的宽度。</Text>
          </Stack>
        </SplitterPanel>
      </Splitter>
    </Card>
  )
}
tsx

用法

import { Splitter, SplitterHandle, SplitterPanel } from '@hina-ui/react'
ts

Splitter 是分栏容器,SplitterPanel 是面板,SplitterHandle 是面板之间可拖动的分隔线。面板与分隔线按顺序交替排列,两个面板之间放一条分隔线。

容器必须有确定的尺寸。横向分栏需要高度,纵向分栏需要高度与宽度,尺寸通过 className 给到 Splitter 上。容器没有高度时面板会塌陷成零高,看起来像没有渲染。

左侧面板

右侧面板

import { Center, Splitter, SplitterHandle, SplitterPanel, Text } from '@hina-ui/react'

export default function Demo() {
  return (
    <Splitter className="border-line h-48 w-full max-w-xl rounded-lg border">
      <SplitterPanel>
        <Center className="h-full">
          <Text size="sm" tone="muted">
            左侧面板
          </Text>
        </Center>
      </SplitterPanel>
      <SplitterHandle />
      <SplitterPanel>
        <Center className="h-full">
          <Text size="sm" tone="muted">
            右侧面板
          </Text>
        </Center>
      </SplitterPanel>
    </Splitter>
  )
}
tsx

面板尺寸一律是百分比,取值 0 到 100,不接受像素值。

示例

方向

direction 决定分栏轴向,默认为 horizontal,即左右分栏;vertical 为上下分栏。分隔线的朝向、拖动方向与键盘方向键都随之改变,不需要另行配置。

上方面板

下方面板

import { Center, Splitter, SplitterHandle, SplitterPanel, Text } from '@hina-ui/react'

export default function Demo() {
  return (
    <Splitter direction="vertical" className="border-line h-64 w-full max-w-xl rounded-lg border">
      <SplitterPanel defaultSize={40}>
        <Center className="h-full">
          <Text size="sm" tone="muted">
            上方面板
          </Text>
        </Center>
      </SplitterPanel>
      <SplitterHandle />
      <SplitterPanel defaultSize={60}>
        <Center className="h-full">
          <Text size="sm" tone="muted">
            下方面板
          </Text>
        </Center>
      </SplitterPanel>
    </Splitter>
  )
}
tsx

尺寸约束

defaultSize 是面板的初始占比,minSize 与 maxSize 是拖动的下限与上限。三者都是百分比。不指定 defaultSize 时,剩余空间在未指定的面板之间均分。

约束用于防止面板被拖到不可用的宽度,例如目录窄到读不出条目。

同一组内要么都给 defaultSize,要么都不给。均分是在浏览器里算出来的,服务端不知道容器尺寸,未指定的面板只能退回等分基准;此时若相邻面板给了 defaultSize,服务端渲染的第一帧比例会明显失真,进入浏览器后才跳回正确值。都不指定则各占等份,服务端与浏览器一致。

侧栏

15% – 40%

主区域

import { Center, Splitter, SplitterHandle, SplitterPanel, Stack, Text } from '@hina-ui/react'

export default function Demo() {
  return (
    <Splitter className="border-line h-48 w-full max-w-xl rounded-lg border">
      <SplitterPanel defaultSize={25} minSize={15} maxSize={40}>
        <Center className="h-full px-3">
          <Stack gap="none" align="center">
            <Text size="sm" tone="muted">
              侧栏
            </Text>
            <Text size="sm" tone="faint">
              15% – 40%
            </Text>
          </Stack>
        </Center>
      </SplitterPanel>
      <SplitterHandle />
      <SplitterPanel defaultSize={75}>
        <Center className="h-full">
          <Text size="sm" tone="muted">
            主区域
          </Text>
        </Center>
      </SplitterPanel>
    </Splitter>
  )
}
tsx

可收起

collapsible 允许面板被拖到 collapsedSize 并停在那里,松手后不会弹回 minSize。collapsedSize 默认为 0,即完全收起。

这与 minSize 是两件事:minSize 是拖动过程中的下限,collapsible 则是越过下限后吸附到收起态。

向左拖至边缘即可收起

主区域

import { Center, Splitter, SplitterHandle, SplitterPanel, Text } from '@hina-ui/react'

export default function Demo() {
  return (
    <Splitter className="border-line h-48 w-full max-w-xl rounded-lg border">
      <SplitterPanel collapsible collapsedSize={0} defaultSize={28} minSize={18}>
        <Center className="h-full px-3">
          <Text size="sm" tone="muted">
            向左拖至边缘即可收起
          </Text>
        </Center>
      </SplitterPanel>
      <SplitterHandle />
      <SplitterPanel defaultSize={72}>
        <Center className="h-full">
          <Text size="sm" tone="muted">
            主区域
          </Text>
        </Center>
      </SplitterPanel>
    </Splitter>
  )
}
tsx

嵌套

面板内可以再放一个 Splitter,方向通常与外层相反,用于「目录 + 编辑 + 预览」这类三分区布局。内层容器用 h-full 撑满所在面板。

目录

编辑

预览

import { Center, Splitter, SplitterHandle, SplitterPanel, Text } from '@hina-ui/react'

export default function Demo() {
  return (
    <Splitter className="border-line h-64 w-full max-w-xl rounded-lg border">
      <SplitterPanel defaultSize={30} minSize={20}>
        <Center className="h-full">
          <Text size="sm" tone="muted">
            目录
          </Text>
        </Center>
      </SplitterPanel>
      <SplitterHandle />
      <SplitterPanel defaultSize={70}>
        <Splitter direction="vertical" className="h-full">
          <SplitterPanel defaultSize={65}>
            <Center className="h-full">
              <Text size="sm" tone="muted">
                编辑
              </Text>
            </Center>
          </SplitterPanel>
          <SplitterHandle />
          <SplitterPanel defaultSize={35}>
            <Center className="h-full">
              <Text size="sm" tone="muted">
                预览
              </Text>
            </Center>
          </SplitterPanel>
        </Splitter>
      </SplitterPanel>
    </Splitter>
  )
}
tsx

记住尺寸

autoSaveId 会把当前比例存入浏览器本地存储,下次进入页面时恢复。同一页面上的多个分栏要用不同的标识,否则会互相覆盖。

标识一旦发布就不宜更改,改动后用户已保存的比例会失效并退回默认值。

调整后刷新页面

宽度会保留

主区域

import { Center, Splitter, SplitterHandle, SplitterPanel, Stack, Text } from '@hina-ui/react'

export default function Demo() {
  return (
    <Splitter
      autoSaveId="hina-docs-splitter-demo"
      className="border-line h-48 w-full max-w-xl rounded-lg border"
    >
      <SplitterPanel defaultSize={35} minSize={20}>
        <Center className="h-full px-3">
          <Stack gap="none" align="center">
            <Text size="sm" tone="muted">
              调整后刷新页面
            </Text>
            <Text size="sm" tone="faint">
              宽度会保留
            </Text>
          </Stack>
        </Center>
      </SplitterPanel>
      <SplitterHandle />
      <SplitterPanel defaultSize={65}>
        <Center className="h-full">
          <Text size="sm" tone="muted">
            主区域
          </Text>
        </Center>
      </SplitterPanel>
    </Splitter>
  )
}
tsx

分隔线名称

分隔线自带无障碍名,随界面语言给出。当页面上有多条分隔线、仅凭默认名称无法区分时,用 label 分别命名。

目录

正文

import { Center, Splitter, SplitterHandle, SplitterPanel, Text } from '@hina-ui/react'

export default function Demo() {
  return (
    <Splitter className="border-line h-48 w-full max-w-xl rounded-lg border">
      <SplitterPanel defaultSize={35}>
        <Center className="h-full">
          <Text size="sm" tone="muted">
            目录
          </Text>
        </Center>
      </SplitterPanel>
      <SplitterHandle label="调整目录宽度" />
      <SplitterPanel defaultSize={65}>
        <Center className="h-full">
          <Text size="sm" tone="muted">
            正文
          </Text>
        </Center>
      </SplitterPanel>
    </Splitter>
  )
}
tsx

无障碍

  • 分隔线可获得焦点,聚焦时显示焦点环;方向键按固定步长调整比例,与拖动等效。
  • 分隔线的角色与当前比例由底层原语给出,屏幕阅读器会读出名称与当前百分比。
  • 默认无障碍名取自界面语言(简体中文为「调整面板大小」),label 可覆盖。多条分隔线并存时应当分别命名。
  • 分隔线不是装饰,不要用 aria-hidden 或负 tabIndex 把它从焦点序列中移除,那会让键盘用户无法调整比例。

API

Splitter

属性
类型
默认值
说明
direction
'horizontal' | 'vertical'
'horizontal'
分栏轴向
autoSaveId
string
—
本地存储中记录比例的标识
className
string
—
追加到根元素的类
属性
说明
children
交替排列的面板与分隔线

SplitterPanel

属性
类型
默认值
说明
defaultSize
number
—
初始占比,百分比
minSize
number
—
拖动下限,百分比
maxSize
number
100
拖动上限,百分比
collapsible
boolean
false
越过下限后是否吸附到收起态
collapsedSize
number
0
收起态的占比,百分比
className
string
—
追加到根元素的类
属性
说明
children
面板内容

SplitterHandle

属性
类型
默认值
说明
label
string
取自界面语言
分隔线的无障碍名
className
string
—
追加到根元素的类