Utilisation
Utilisez le composant Splitter pour afficher une liste de panneaux redimensionnables séparés par des poignées glissables.
<script setup lang="ts">
import type { SplitterItem } from '@nuxt/ui'
const card = 'bg-elevated/50 border border-default rounded-xl items-center justify-center text-muted font-medium'
const items: SplitterItem[] = [
{ slot: 'left', minSize: 15, defaultSize: 25, class: card },
{ slot: 'main', minSize: 30, defaultSize: 50, class: card },
{ slot: 'right', minSize: 15, defaultSize: 25, class: card }
]
</script>
<template>
<div class="w-full h-96">
<USplitter id="splitter-example" :items="items">
<template #left>
Left
</template>
<template #main>
Main
</template>
<template #right>
Right
</template>
</USplitter>
</div>
</template>
Éléments
Utilisez le prop items comme un tableau d'objets avec les propriétés suivantes:
Xph007xxxdefaultSize?: numberxxxxph000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
- x
minSize?: numberx{lang="ts-type"} - x
maxSize?: numberxx{lang="ts-type"} - x
collapsible?: booleanxx{lang="ts-type"} - x
collapsedSize?: numberxx{lang="ts-type"} - x
sizeUnit?: '%' | 'px'xx{lang="ts-type"} - x
order?: numberx{lang="ts-type"} - x
id?: stringx{lang="ts-type"} - x
slot?: stringxx{lang="ts-type"} - x
class?: anyx{lang="ts-type"} - x
ui?: { panel?: ClassNameValue }xx{lang="ts-type"}
Utilisez la touche slot pour remplir le contenu d'un panneau et la touche class pour le styliser. Les éléments sans touche slot retombent dans un emplacement panel-{index}. Les tailles sont des pourcentages par défaut, définissez sizeUnit: 'px' sur un élément pour les valeurs de pixels.
id et donnez defaultSize à tous les éléments ou à aucun. Les identifiants sont générés automatiquement sinon et le serveur et le client peuvent être en désaccord, ce qui rompt la disposition sur l'hydratation. Un élément sans defaultSize retombe à une part égale sur le serveur, donc mélanger les deux fait sauter les panneaux une fois hydratés. Les tailles de pixels sont mesurées sur le client et changent toujours un peu.<script setup lang="ts">
import type { SplitterItem } from '@nuxt/ui'
const items = ref<SplitterItem[]>([
{
slot: 'sidebar',
minSize: 15,
maxSize: 40,
defaultSize: 25,
class:
'bg-elevated/50 border border-default rounded-xl items-center justify-center text-muted font-medium'
},
{
slot: 'main',
defaultSize: 75,
class:
'bg-elevated/50 border border-default rounded-xl items-center justify-center text-muted font-medium'
}
])
</script>
<template>
<USplitter id="splitter-items" :items="items">
<template #sidebar> Sidebar </template>
<template #main> Main </template>
</USplitter>
</template><script setup lang="ts">
import { ref } from 'vue'
import type { SplitterItem } from '@nuxt/ui'
const items = ref<SplitterItem[]>([
{
slot: 'sidebar',
minSize: 15,
maxSize: 40,
defaultSize: 25,
class:
'bg-elevated/50 border border-default rounded-xl items-center justify-center text-muted font-medium'
},
{
slot: 'main',
defaultSize: 75,
class:
'bg-elevated/50 border border-default rounded-xl items-center justify-center text-muted font-medium'
}
])
</script>
<template>
<USplitter id="splitter-items" :items="items">
<template #sidebar> Sidebar </template>
<template #main> Main </template>
</USplitter>
</template>Définition
Utilisez la prop orientation pour changer la direction du séparateur. Par défaut, horizontal.
<script setup lang="ts">
import type { SplitterItem } from '@nuxt/ui'
const items = ref<SplitterItem[]>([
{
slot: 'first',
class:
'bg-elevated/50 border border-default rounded-xl items-center justify-center text-muted font-medium'
},
{
slot: 'second',
class:
'bg-elevated/50 border border-default rounded-xl items-center justify-center text-muted font-medium'
}
])
</script>
<template>
<USplitter id="splitter-orientation" orientation="vertical" :items="items">
<template #first> First </template>
<template #second> Second </template>
</USplitter>
</template><script setup lang="ts">
import { ref } from 'vue'
import type { SplitterItem } from '@nuxt/ui'
const items = ref<SplitterItem[]>([
{
slot: 'first',
class:
'bg-elevated/50 border border-default rounded-xl items-center justify-center text-muted font-medium'
},
{
slot: 'second',
class:
'bg-elevated/50 border border-default rounded-xl items-center justify-center text-muted font-medium'
}
])
</script>
<template>
<USplitter id="splitter-orientation" orientation="vertical" :items="items">
<template #first> First </template>
<template #second> Second </template>
</USplitter>
</template>Exemples
Avec panneau pliable
Définissez collapsible: true sur un élément pour le laisser s'effondrer au-delà de son minSize, et utilisez collapsedSize pour garder une partie du panneau visible lorsqu 'il est effondré. L'emplacement du panneau expose collapsed, collapse et expand afin que vous puissiez le contrôler par programmation, et les événements collapse, expand et resize se déclenchent avec l'index du panneau.
<script setup lang="ts">
import type { SplitterItem } from '@nuxt/ui'
const items: SplitterItem[] = [
{ slot: 'sidebar', sizeUnit: 'px', minSize: 150, defaultSize: 250, collapsible: true, collapsedSize: 48, class: 'bg-elevated/50 border border-default rounded-xl' },
{ slot: 'main', class: 'bg-elevated/50 border border-default rounded-xl items-center justify-center text-muted font-medium' }
]
</script>
<template>
<div class="w-full h-96">
<USplitter id="splitter-collapsible-example" :items="items">
<template #sidebar="{ collapsed, collapse, expand }">
<div class="flex-1 flex items-center justify-center p-2">
<UButton
:icon="collapsed ? 'i-lucide-panel-left-open' : 'i-lucide-panel-left-close'"
:label="collapsed ? undefined : 'Collapse'"
:aria-label="collapsed ? 'Expand' : undefined"
color="neutral"
variant="subtle"
@click="collapsed ? expand() : collapse()"
/>
</div>
</template>
<template #main>
Main
</template>
</USplitter>
</div>
</template>
Avec splitters imbriqués
Installer un Splitter à l'intérieur d'un panneau pour créer des mises en page bidimensionnelles de style IDE.
<script setup lang="ts">
import type { SplitterItem } from '@nuxt/ui'
const card = 'bg-elevated/50 border border-default rounded-xl items-center justify-center text-muted font-medium'
const items: SplitterItem[] = [
{ slot: 'left', minSize: 20, class: card },
{ slot: 'right', minSize: 20 }
]
const nested: SplitterItem[] = [
{ slot: 'top', minSize: 20, class: card },
{ slot: 'bottom', minSize: 20, class: card }
]
</script>
<template>
<div class="w-full h-96">
<USplitter id="splitter-nested-example" :items="items">
<template #left>
Left
</template>
<template #right>
<USplitter id="splitter-nested-example-inner" orientation="vertical" :items="nested">
<template #top>
Top
</template>
<template #bottom>
Bottom
</template>
</USplitter>
</template>
</USplitter>
</div>
</template>
Avec poignée personnalisée
Utilisez le prop ui pour le restyler, par exemple en tant que diviseur visible pour les mises en page affleurantes, et le slot resize-handle pour rendre le contenu à l'intérieur comme une poignée.
<script setup lang="ts">
import type { SplitterItem } from '@nuxt/ui'
const items: SplitterItem[] = [
{ slot: 'left', minSize: 20, defaultSize: 30, class: 'items-center justify-center text-muted font-medium' },
{ slot: 'right', defaultSize: 70, class: 'items-center justify-center text-muted font-medium' }
]
</script>
<template>
<div class="w-full h-96">
<USplitter id="splitter-custom-handle-example" :items="items" :ui="{ handle: 'data-[orientation=horizontal]:w-px data-[orientation=vertical]:h-px bg-border transition-colors data-[state=hover]:bg-primary data-[state=drag]:bg-primary' }" class="rounded-lg border border-default overflow-hidden">
<template #left>
Left
</template>
<template #right>
Right
</template>
</USplitter>
</div>
</template>
avec persistance
Fournissez un auto-save-id pour conserver la disposition sur localStorage et la restaurer lors du rechargement.
<template>
<USplitter id="my-layout" auto-save-id="my-layout" :items="items">
<!-- ... -->
</USplitter>
</template>
API
Props équipements
| Prop | Default | Type |
|---|---|---|
as | 'div' | anyThe element or component this component should render as. |
id | stringA unique id for the group, also used to derive the ids of its panels and handles. Set it when rendering on the server, auto-generated ids can differ between the server and the client and break resizing on hydration. | |
orientation | 'horizontal' | "horizontal" | "vertical"The orientation of the splitter. |
items | T[] | |
disabled | false | boolean Whether the resize handles are disabled, locking the current layout. |
autoSaveId | null | stringUnique id used to auto-save group arrangement via | |
keyboardResizeBy | null | numberStep size when arrow key was pressed. | |
storage | PanelGroupStorageCustom storage API; defaults to localStorage | |
hitAreaMargins | PointerHitAreaMarginsAllow this much margin when determining resizable handle hit detection | |
ui | { root?: SlotClass; panel?: SlotClass; handle?: SlotClass; } |
Slots
| Slot | Type |
|---|---|
resize-handle | { index: number; ui: object; } |
Emits
| Event | Type |
|---|---|
layout | [val: number[]] |
collapse | [index: number] |
expand | [index: number] |
resize | [index: number, size: number, prevSize?: number | undefined] |
dragging | [index: number, dragging: boolean] |
Thème
export default defineAppConfig({
ui: {
splitter: {
slots: {
root: '',
panel: 'flex',
handle: 'group relative shrink-0 focus-visible:outline-2 focus-visible:outline-primary data-[panel-resize-handle-enabled=false]:cursor-default'
},
variants: {
orientation: {
horizontal: {
handle: 'w-2 cursor-col-resize'
},
vertical: {
handle: 'h-2 cursor-row-resize'
}
}
}
}
}
})import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'
export default defineConfig({
plugins: [
vue(),
ui({
ui: {
splitter: {
slots: {
root: '',
panel: 'flex',
handle: 'group relative shrink-0 focus-visible:outline-2 focus-visible:outline-primary data-[panel-resize-handle-enabled=false]:cursor-default'
},
variants: {
orientation: {
horizontal: {
handle: 'w-2 cursor-col-resize'
},
vertical: {
handle: 'h-2 cursor-row-resize'
}
}
}
}
}
})
]
})