Skip to content
API 风格:

Cajón ​

Panel lateral que se desliza desde el borde de la pantalla; resulta adecuado para operaciones temporales más pegadas a los bordes que un Dialog (detalles, filtrado, pasos de un asistente). Al igual que Dialog, emplea role="dialog" + aria-modal="true", el foco queda encerrado en el panel y tanto Esc como el clic en la máscara pueden cerrarlo.

Uso básico ​

Cajón derecho
vue
<template>
  <LhButton @click="basic = true">Abrir cajón</LhButton>
  <LhDrawer v-model="basic" title="Detalles del pedido">
    <p>Aquí se coloca el contenido principal del cajón.</p>
  </LhDrawer>
</template>

<script setup lang="ts">
import { ref } from 'vue'
const basic = ref(false)
</script>
vue
<script>
export default {
  data() {
    return { basic: false }
  },
}
</script>

<template>
  <LhButton @click="basic = true">Abrir cajón</LhButton>
  <LhDrawer v-model="basic" title="Detalles del pedido">
    <p>Aquí se coloca el contenido principal del cajón.</p>
  </LhDrawer>
</template>

Cuatro direcciones ​

right / left / top / bottom
vue
<script setup lang="ts">
import { ref } from 'vue'
const dirVisible = ref(false)
const direction = ref<'right' | 'left' | 'top' | 'bottom'>('right')
const size = ref('40%')
function openDir(d: 'right' | 'left' | 'top' | 'bottom') {
  direction.value = d
  dirVisible.value = true
}
</script>

<template>
  <!-- Abrir el cajón derecho -->
  <LhButton @click="openDir('right')">right</LhButton>
  <!-- Abrir el cajón izquierdo -->
  <LhButton @click="openDir('left')">left</LhButton>
  <!-- Abrir el cajón superior -->
  <LhButton @click="openDir('top')">top</LhButton>
  <!-- Abrir el cajón inferior -->
  <LhButton @click="openDir('bottom')">bottom</LhButton>
  <!-- Se desliza en la dirección indicada -->
  <LhDrawer v-model="dirVisible" :title="`Cajón ${direction}`" :direction="direction" :size="size">
    <p>Dirección actual: {{ direction }}</p>
  </LhDrawer>
</template>
vue
<script>
export default {
  data() {
    return { dirVisible: false, direction: 'right', size: '40%' }
  },
  methods: {
    openDir(d) {
      this.direction = d
      this.dirVisible = true
    },
  },
}
</script>

<template>
  <!-- Abrir el cajón derecho -->
  <LhButton @click="openDir('right')">right</LhButton>
  <!-- Abrir el cajón izquierdo -->
  <LhButton @click="openDir('left')">left</LhButton>
  <!-- Abrir el cajón superior -->
  <LhButton @click="openDir('top')">top</LhButton>
  <!-- Abrir el cajón inferior -->
  <LhButton @click="openDir('bottom')">bottom</LhButton>
  <!-- Se desliza en la dirección indicada -->
  <LhDrawer v-model="dirVisible" :title="`Cajón ${direction}`" :direction="direction" :size="size">
    <p>Dirección actual: {{ direction }}</p>
  </LhDrawer>
</template>

Tamaño personalizado y zona inferior ​

size y slot footer
vue
<script setup lang="ts">
import { ref } from 'vue'

const sized = ref(false)
</script>

<template>
  <!-- Abrir un cajón de 480 px de ancho -->
  <LhButton @click="sized = true">Cajón de 480 px de ancho</LhButton>
  <!-- Cajón de tamaño fijo; la zona inferior es el área de acciones -->
  <LhDrawer v-model="sized" title="Condiciones del filtro" :size="480">
    <LhInput placeholder="Filtrar por nombre" />
    <LhInput placeholder="Filtrar por etiqueta" />
    <template #footer>
      <LhButton @click="sized = false">Cancelar</LhButton>
      <LhButton type="primary" @click="sized = false">Aplicar filtro</LhButton>
    </template>
  </LhDrawer>
</template>
vue
<script>
export default {
  data() {
    return { sized: false }
  },
}
</script>

<template>
  <!-- Abrir un cajón de 480 px de ancho -->
  <LhButton @click="sized = true">Cajón de 480 px de ancho</LhButton>
  <!-- Cajón de tamaño fijo; la zona inferior es el área de acciones -->
  <LhDrawer v-model="sized" title="Condiciones del filtro" :size="480">
    <LhInput placeholder="Filtrar por nombre" />
    <LhInput placeholder="Filtrar por etiqueta" />
    <template #footer>
      <LhButton @click="sized = false">Cancelar</LhButton>
      <LhButton type="primary" @click="sized = false">Aplicar filtro</LhButton>
    </template>
  </LhDrawer>
</template>

Si size recibe un número, se interpreta como px; si recibe una cadena, admite porcentajes (p. ej., '40%'). En las direcciones izquierda/derecha actúa sobre la anchura, y en las direcciones superior/inferior, sobre la altura.

Interruptores de comportamiento ​

mask-closable impide el cierre al hacer clic en la máscara; show-close oculta el botón de cierre de la esquina superior derecha; close-on-esc desactiva el cierre con Esc; lock-scroll evita que se bloquee el desplazamiento de la página al abrir; teleport-target especifica el contenedor de montaje.

Interruptores de comportamiento
vue
<script setup lang="ts">
import { ref } from 'vue'

const adv1 = ref(false)
const adv2 = ref(false)
const adv3 = ref(false)
</script>

<template>
  <!-- Abrir el cajón «Cerrar solo con el botón» -->
  <LhButton @click="adv1 = true">Cerrar solo con el botón</LhButton>
  <!-- Abrir el cajón «Sin bloqueo del desplazamiento» -->
  <LhButton @click="adv2 = true">Sin bloqueo del desplazamiento</LhButton>
  <!-- Ni el clic en la máscara ni Esc cierran el panel -->
  <LhDrawer
    v-model="adv1"
    title="Cerrar solo con el botón"
    :mask-closable="false"
    :show-close="false"
    :close-on-esc="false"
  >
    <p>Ni el clic en la máscara ni Esc cierran el panel: solo puede cerrarse con el botón.</p>
    <template #footer>
      <LhButton type="primary" @click="adv1 = false">Cerrar</LhButton>
    </template>
  </LhDrawer>
  <!-- Al abrir, la página sigue pudiéndose desplazar -->
  <LhDrawer v-model="adv2" title="Sin bloqueo del desplazamiento" :lock-scroll="false">
    <p>Con el cajón abierto, la página sigue pudiéndose desplazar.</p>
  </LhDrawer>
  <!-- Montar en el contenedor especificado -->
  <LhDrawer v-model="adv3" title="Contenedor de montaje especificado" teleport-target="#drawer-host">
    <p>El panel se transmite al contenedor cuyo id es drawer-host.</p>
  </LhDrawer>
</template>
vue
<script>
export default {
  data() {
    return { adv1: false, adv2: false, adv3: false }
  },
}
</script>

<template>
  <!-- Abrir el cajón «Cerrar solo con el botón» -->
  <LhButton @click="adv1 = true">Cerrar solo con el botón</LhButton>
  <!-- Abrir el cajón «Sin bloqueo del desplazamiento» -->
  <LhButton @click="adv2 = true">Sin bloqueo del desplazamiento</LhButton>
  <!-- Ni el clic en la máscara ni Esc cierran el panel -->
  <LhDrawer
    v-model="adv1"
    title="Cerrar solo con el botón"
    :mask-closable="false"
    :show-close="false"
    :close-on-esc="false"
  >
    <p>Ni el clic en la máscara ni Esc cierran el panel: solo puede cerrarse con el botón.</p>
    <template #footer>
      <LhButton type="primary" @click="adv1 = false">Cerrar</LhButton>
    </template>
  </LhDrawer>
  <!-- Al abrir, la página sigue pudiéndose desplazar -->
  <LhDrawer v-model="adv2" title="Sin bloqueo del desplazamiento" :lock-scroll="false">
    <p>Con el cajón abierto, la página sigue pudiéndose desplazar.</p>
  </LhDrawer>
  <!-- Montar en el contenedor especificado -->
  <LhDrawer v-model="adv3" title="Contenedor de montaje especificado" teleport-target="#drawer-host">
    <p>El panel se transmite al contenedor cuyo id es drawer-host.</p>
  </LhDrawer>
</template>

Drawer API ​

Props ​

PropDescripciónTipoPredeterminado
modelValueSi se muestra (v-model)boolean—
titleTítulo (también puede usar el slot header)string—
directionDirección"right" | "left" | "top" | "bottom"'right'
sizeTamaño: un número son px; una cadena admite porcentajesstring | number'30%'
maskClosableSi se cierra al hacer clic en la máscarabooleantrue
showCloseSi se muestra el botón de cierrebooleantrue
teleportTargetObjetivo del Teleport (selector o elemento; por defecto, body)string | HTMLElement'body'
lockScrollSi se bloquea el desplazamiento de la páginabooleantrue
closeOnEscSi responde al cierre con Escbooleantrue
themeVarsVariables de tema a nivel de componente; sobrescribe la configuración del ConfigProvider{ [x: string]: string; }—
bgPatternPatrón de fondo a nivel de componente; sobrescribe la configuración del ConfigProviderstring—
sxProps de disposición rápida (aplicadas al panel)LhSxProps—

Events ​

EventoDescripciónParámetros
update:model-valueCambio de visibilidad(value: boolean)
openSe dispara tras abrir—
closeSe dispara tras cerrar—

Slots ​

SlotDescripción
defaultContenido principal
headerCabecera personalizada (incluye la zona del título)
footerZona inferior de acciones personalizada

Methods ​

MétodoDescripción
openApertura programática
closeCierre programático

Accesibilidad ​

  • role="dialog" + aria-modal="true"; cuando hay título se asocia mediante aria-labelledby, y cuando no lo hay se usa drawer.title del paquete de idioma como valor de respaldo de aria-label
  • Al abrirse, el foco pasa al primer elemento enfocable del panel; Tab queda encerrado en el panel y, al cerrar, el foco regresa al elemento que lo abrió
  • Cierre con Esc (puede desactivarse con close-on-esc); la máscara es decorativa (aria-hidden)
  • El botón de cierre es un <button> real; su aria-label procede de drawer.close del paquete de idioma
  • La animación de deslizamiento al entrar y salir se degrada a un simple fundido cuando está activo prefers-reduced-motion

Definiciones de tipos ​

Las estructuras de tipos TypeScript exportadas por este componente (extraídas automáticamente de packages/components/drawer/src/types.ts y de las fuentes @lh-ui/share/core/*; abre cada entrada para ver la definición completa; la descripción de los atributos está en la tabla de Props de arriba):

LhDrawerProps
ts
export interface LhDrawerProps {
  /** Si se muestra (v-model) */
  modelValue?: boolean
  /** Título */
  title?: string
  /** Dirección */
  direction?: LhDrawerDirection
  /** Tamaño: un número son px; una cadena admite porcentajes */
  size?: string | number
  /** Si se cierra al hacer clic en la máscara */
  maskClosable?: boolean
  /** Si se muestra el botón de cierre */
  showClose?: boolean
  /** Objetivo del Teleport (selector o elemento; por defecto, body) */
  teleportTarget?: string | HTMLElement
  /** Si se bloquea el desplazamiento de la página */
  lockScroll?: boolean
  /** Si responde al cierre con Esc */
  closeOnEsc?: boolean
  /** Variables de tema a nivel de componente; sobrescribe la configuración del ConfigProvider */
  themeVars?: Record<string, string>
  /** Patrón de fondo a nivel de componente; sobrescribe la configuración del ConfigProvider */
  bgPattern?: string
  /** Props de disposición rápida (aplicadas al panel) */
  sx?: LhSxProps
}
LhDrawerDirection (de @lh-ui/share/core/drawer (logic.ts))
ts
/**
 * Lógica de funciones puras de Drawer (sin dependencias de framework)
 */

/** Dirección del cajón */
export type LhDrawerDirection = 'right' | 'left' | 'top' | 'bottom'

La belleza de la tradición, el cimiento del código