#Resizable 可调整面板
允许用户通过拖拽调整容器大小的组件,支持 2D 调整、比例锁定以及面板分割。
#组件特性
- ↔️ 8 个 resize 方向:支持上、下、左、右及其四角组合。
- 📐 比例锁定:支持在调整大小时锁定宽高比。
- 📊 网格吸附:支持基于网格的精确对齐吸附。
- ⌨️ 键盘调整:支持基于键盘的调整大小操作。
- 📋 面板拆分:支持拖拽拆分面板,带调整手柄。
- 📏 尺寸约束:支持
minWidth、maxWidth、minHeight、maxHeight约束。 - 🎨 主题定制:基于
BrConfigProvider支持全局主题配置和 TailwindCSS 局部覆盖。
#基础用法
支持在水平或垂直方向上调整大小,也可以在多个方向上同时调整。
<script setup lang="ts">
import { ref } from 'vue'
import { BrResizable, BrResizableHandle } from '@breezeui/vue'
const width = ref(300)
const height = ref(200)
</script>
<template>
<BrResizable
v-model:width="width"
v-model:height="height"
:min-width="150"
:min-height="100"
:max-width="500"
:max-height="400"
class="border border-border rounded-lg bg-muted/20 flex items-center justify-center relative shadow-sm"
>
<div class="text-center">
<div class="font-medium text-foreground">Basic Resizable</div>
<div class="text-sm text-muted-foreground">{{ Math.round(width) }}px x {{ Math.round(height) }}px</div>
</div>
<template #handle="{ onDragStart }">
<BrResizableHandle direction="right" class="bg-primary/50 hover:bg-primary w-2" @drag-start="onDragStart($event, 'right')" />
<BrResizableHandle direction="bottom" class="bg-primary/50 hover:bg-primary h-2" @drag-start="onDragStart($event, 'bottom')" />
<BrResizableHandle direction="bottom-right" class="bg-primary/50 hover:bg-primary w-4 h-4 rounded-tl-lg" @drag-start="onDragStart($event, 'bottom-right')" />
</template>
</BrResizable>
</template>#锁定比例
通过设置 lock-aspect-ratio 属性可以锁定调整时的宽高比。
<script setup lang="ts">
import { ref } from 'vue'
import { BrResizable } from '@breezeui/vue'
const width = ref(300)
const height = ref(168.75) // 16:9 ratio
</script>
<template>
<BrResizable
v-model:width="width"
v-model:height="height"
:lock-aspect-ratio="16/9"
:min-width="200"
:max-width="600"
class="border border-border rounded-lg overflow-hidden relative shadow-sm"
>
<img
src="https://images.unsplash.com/photo-1682687220063-4742bd7fd538?q=80&w=2070&auto=format&fit=crop"
class="w-full h-full object-cover pointer-events-none"
alt="demo"
/>
<div class="absolute inset-0 flex items-center justify-center bg-black/30 text-white font-medium">
16:9 ({{ Math.round(width) }} x {{ Math.round(height) }})
</div>
</BrResizable>
</template>#面板分割
结合 BrResizableSplit 和 BrResizableSplitPane 可以创建多面板分割布局。
<script setup lang="ts">
import {
BrResizableSplit,
BrResizableSplitPane,
BrResizableHandle
} from '@breezeui/vue'
</script>
<template>
<BrResizableSplit direction="horizontal" class="h-[300px] w-full rounded-lg border shadow-sm">
<BrResizableSplitPane :default-size="25" :min-size="15">
<div class="flex h-full flex-col bg-muted/10">
<div class="p-4 font-medium border-b">Sidebar</div>
<div class="p-4 text-sm text-muted-foreground flex-1">Keyboard navigation supported</div>
</div>
</BrResizableSplitPane>
<BrResizableHandle split with-handle />
<BrResizableSplitPane :default-size="75">
<BrResizableSplit direction="vertical">
<BrResizableSplitPane :default-size="60">
<div class="flex h-full items-center justify-center bg-background">
<span class="font-medium text-foreground">Main Content</span>
</div>
</BrResizableSplitPane>
<BrResizableHandle split with-handle class="hover:bg-primary/50 transition-colors" />
<BrResizableSplitPane :default-size="40">
<div class="flex h-full items-center justify-center bg-muted/20">
<span class="font-medium text-muted-foreground">Terminal / Console</span>
</div>
</BrResizableSplitPane>
</BrResizableSplit>
</BrResizableSplitPane>
</BrResizableSplit>
</template>#与表格组件集成
Resizable 组件可以轻松与表格组件集成,实现自适应宽度和高度的数据网格。
<script setup lang="ts">
import { ref } from 'vue'
import { BrResizable, BrCard, BrTable } from '@breezeui/vue'
const tableWidth = ref(450)
const tableHeight = ref(300)
const tableData = [
{ id: 1, name: 'John Doe', role: 'Developer' },
{ id: 2, name: 'Jane Smith', role: 'Designer' },
{ id: 3, name: 'Mike Johnson', role: 'Manager' },
]
const columns = [
{ key: 'id', title: 'ID' },
{ key: 'name', title: 'Name' },
{ key: 'role', title: 'Role' },
]
</script>
<template>
<BrResizable
v-model:width="tableWidth"
v-model:height="tableHeight"
:min-width="300"
:min-height="200"
class="flex flex-col"
>
<BrCard class="w-full h-full flex flex-col overflow-hidden">
<div class="p-4 border-b font-medium bg-muted/30">Resizable Table Card</div>
<div class="flex-1 overflow-auto p-4">
<BrTable :data="tableData" :columns="columns" />
</div>
</BrCard>
</BrResizable>
</template>#与卡片组件集成
将卡片放入可调整大小的容器中,并利用卡片内部的滚动区域来展示更多内容。
<script setup lang="ts">
import { ref } from 'vue'
import { BrResizable, BrCard, BrCardHeader, BrCardTitle, BrCardDescription, BrCardContent } from '@breezeui/vue'
const cardWidth = ref(400)
const cardHeight = ref(250)
</script>
<template>
<BrResizable
v-model:width="cardWidth"
v-model:height="cardHeight"
:min-width="250"
:min-height="150"
class="flex flex-col"
>
<BrCard class="w-full h-full flex flex-col overflow-hidden shadow-md">
<BrCardHeader>
<BrCardTitle>Resizable Card</BrCardTitle>
<BrCardDescription>Drag the handle to resize this card component.</BrCardDescription>
</BrCardHeader>
<BrCardContent class="flex-1 overflow-auto text-muted-foreground">
<p class="mb-4">
This is a card component nested inside a resizable container.
Notice how the card header stays fixed while the content area scrolls if it overflows.
</p>
<p>
You can integrate the Resizable component with almost any other UI element to create dynamic layouts.
</p>
</BrCardContent>
</BrCard>
</BrResizable>
</template>#API
#Resizable Props
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| as | 渲染的 HTML 标签 | string | 'div' |
| width / v-model:width | 容器宽度 | number | string | - |
| height / v-model:height | 容器高度 | number | string | - |
| minWidth | 最小宽度 | number | 0 |
| maxWidth | 最大宽度 | number | Infinity |
| minHeight | 最小高度 | number | 0 |
| maxHeight | 最大高度 | number | Infinity |
| directions | 允许调整的方向 | ('top' | 'right' | 'bottom' | 'left' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right')[] | ['right', 'bottom', 'bottom-right'] |
| lockAspectRatio | 锁定宽高比,可传布尔值(锁定初始比例)或具体数字比例 | boolean | number | false |
| grid | 对齐网格大小,可传单数字或 [x, y] 数组 | number | [number, number] | 1 |
| step | 键盘调整时的步长 | number | 10 |
| disabled | 是否禁用 | boolean | false |
#Resizable Emits
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| update:width | 宽度改变时触发 | (width: number) => void |
| update:height | 高度改变时触发 | (height: number) => void |
| resizeStart | 开始调整时触发 | (event: { width: number; height: number; direction: string }) => void |
| resize | 调整过程中触发 | (event: { width: number; height: number; direction: string }) => void |
| resizeEnd | 结束调整时触发 | (event: { width: number; height: number; direction: string }) => void |
#ResizableHandle Props
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| direction | 手柄控制的方向(非 Split 模式使用) | string | - |
| split | 是否作为 Split 模式的手柄 | boolean | false |
| withHandle | Split 模式下是否显示内置图标 | boolean | false |
#ResizableSplit Props
基于 radix-vue 的 SplitterGroup,透传其所有属性。
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| direction | 分割方向 | 'horizontal' | 'vertical' | - |
#ResizableSplitPane Props
基于 radix-vue 的 SplitterPanel,透传其所有属性。
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| defaultSize | 默认尺寸百分比 | number | - |
| minSize | 最小尺寸百分比 | number | 0 |
| maxSize | 最大尺寸百分比 | number | 100 |