Splitter New

Un conjunto de paneles redimensionables separados por asas arrastrables.

xph0000xUso

Utilice el componente Splitter para mostrar una lista de paneles redimensionables separados por manijas arrastrables.

Left
Main
Right
<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>
El Splitter llena la altura de su contenedor, así que asegúrese de que un elemento padre defina uno.

Artículos

Utilice el prop items como una matriz de objetos con las siguientes propiedades:

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

  • xxcollapsedSize?: numberxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  • xxsizeUnit?: '%' | 'px'xx{lang="ts-type"}
  • xxorder?: numberxxx{lang="ts-type"}
  • xxid?: stringxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  • xxslot?: stringxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Utilice la tecla slot para rellenar el contenido de un panel y la tecla class para darle estilo. Los elementos sin una tecla slot se recaen a una ranura panel-{index}. Los tamaños son porcentajes de forma predeterminada, establezca sizeUnit: 'px' en un elemento para los valores de píxeles.

Al renderizar en el servidor, configure el prop id y asigne defaultSize a todos los elementos o a ninguno. Los Ids se generan automáticamente de lo contrario y el servidor y el cliente pueden estar en desacuerdo, lo que rompe el diseño en la hidratación. Un elemento sin un defaultSize vuelve a tener una participación igual en el servidor, por lo que mezclar los dos hace que los paneles salten una vez hidratados. Los tamaños de píxeles se miden en el cliente y siempre cambian un poco.
El sidebar
principales
<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>

Orientación

Utilice el prop orientation para cambiar la dirección del divisor. Predeterminados a horizontal.

Primero
El segundo
<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>

Ejemplos

XPH101XCon panel plegable

Configure collapsible: true en un elemento para que se colapse más allá de su minSize y use collapsedSize para mantener parte del panel visible cuando se colapse. La ranura del panel expone collapsed, collapse y expand para que pueda controlarlo programáticamente, y los eventos collapse, expand y resize se disparan con el índice del panel.

Main
<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>

Con divisores anidados

Anida un Splitter dentro de un panel para crear diseños bidimensionales de estilo IDE.

Left
Top
Bottom
<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>

With handle personalizado

Utilice el soporte ui para rediseñarlo, por ejemplo, como un divisor visible para diseños al ras, y la ranura resize-handle para representar el contenido dentro de él como un agarre.

Left
Right
<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>

Con persistencia

Proporcionar un auto-save-id para mantener el diseño a localStorage y restaurarlo en la recarga.

<template>
  <USplitter id="my-layout" auto-save-id="my-layout" :items="items">
    <!-- ... -->
  </USplitter>
</template>

API

Props (Edición española)

Prop Default Type
as
'div'
any

The element or component this component should render as.

id
string

A 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 | string

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

keyboardResizeBy
null | number

Step size when arrow key was pressed.

storage
PanelGroupStorage

Custom storage API; defaults to localStorage

hitAreaMargins
PointerHitAreaMargins

Allow this much margin when determining resizable handle hit detection

ui
{ root?: SlotClass; panel?: SlotClass; handle?: SlotClass; }

Slots en línea

Slot Type
resize-handle
{ index: number; ui: object; }

Emisiones

Event Type
layout
[val: number[]]
collapse
[index: number]
expand
[index: number]
resize
[index: number, size: number, prevSize?: number | undefined]
dragging
[index: number, dragging: boolean]

Temas

app.config.ts
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'
          }
        }
      }
    }
  }
})
vite.config.ts
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'
              }
            }
          }
        }
      }
    })
  ]
})

Changelog (Edición española)

No recent changes