Skip to content
API 风格:

Выдвижная панель ​

Боковая сдвижная панель, выезжающая от края экрана; подходит для временных действий, располагающихся ближе к краю, чем Dialog (подробности, фильтры, шаги мастера). Как и Dialog, использует role="dialog" + aria-modal="true"; фокус удерживается внутри панели, закрытие возможно по Esc и нажатием на маску.

Базовое использование ​

Правая панель
vue
<template>
  <LhButton @click="basic = true">Открыть панель</LhButton>
  <LhDrawer v-model="basic" title="Детали заказа">
    <p>Здесь размещается основное содержимое панели.</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">Открыть панель</LhButton>
  <LhDrawer v-model="basic" title="Детали заказа">
    <p>Здесь размещается основное содержимое панели.</p>
  </LhDrawer>
</template>

Четыре направления ​

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>
  <!-- Открыть правую панель -->
  <LhButton @click="openDir('right')">right</LhButton>
  <!-- Открыть левую панель -->
  <LhButton @click="openDir('left')">left</LhButton>
  <!-- Открыть верхнюю панель -->
  <LhButton @click="openDir('top')">top</LhButton>
  <!-- Открыть нижнюю панель -->
  <LhButton @click="openDir('bottom')">bottom</LhButton>
  <!-- Выезд в указанном направлении -->
  <LhDrawer v-model="dirVisible" :title="`Панель: ${direction}`" :direction="direction" :size="size">
    <p>Текущее направление: {{ 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>
  <!-- Открыть правую панель -->
  <LhButton @click="openDir('right')">right</LhButton>
  <!-- Открыть левую панель -->
  <LhButton @click="openDir('left')">left</LhButton>
  <!-- Открыть верхнюю панель -->
  <LhButton @click="openDir('top')">top</LhButton>
  <!-- Открыть нижнюю панель -->
  <LhButton @click="openDir('bottom')">bottom</LhButton>
  <!-- Выезд в указанном направлении -->
  <LhDrawer v-model="dirVisible" :title="`Панель: ${direction}`" :direction="direction" :size="size">
    <p>Текущее направление: {{ direction }}</p>
  </LhDrawer>
</template>

Пользовательский размер и нижняя область ​

size и слот footer
vue
<script setup lang="ts">
import { ref } from 'vue'

const sized = ref(false)
</script>

<template>
  <!-- Открыть панель шириной 480px -->
  <LhButton @click="sized = true">Панель шириной 480px</LhButton>
  <!-- Панель фиксированного размера, внизу — область действий -->
  <LhDrawer v-model="sized" title="Условия фильтрации" :size="480">
    <LhInput placeholder="Фильтр по названию" />
    <LhInput placeholder="Фильтр по тегам" />
    <template #footer>
      <LhButton @click="sized = false">Отмена</LhButton>
      <LhButton type="primary" @click="sized = false">Применить фильтр</LhButton>
    </template>
  </LhDrawer>
</template>
vue
<script>
export default {
  data() {
    return { sized: false }
  },
}
</script>

<template>
  <!-- Открыть панель шириной 480px -->
  <LhButton @click="sized = true">Панель шириной 480px</LhButton>
  <!-- Панель фиксированного размера, внизу — область действий -->
  <LhDrawer v-model="sized" title="Условия фильтрации" :size="480">
    <LhInput placeholder="Фильтр по названию" />
    <LhInput placeholder="Фильтр по тегам" />
    <template #footer>
      <LhButton @click="sized = false">Отмена</LhButton>
      <LhButton type="primary" @click="sized = false">Применить фильтр</LhButton>
    </template>
  </LhDrawer>
</template>

Если в size передать число, это пиксели; строка поддерживает проценты (например '40%'). Для направления влево/вправо параметр задаёт ширину, для вверх/вниз — высоту.

Поведенческие переключатели ​

mask-closable запрещает закрытие по нажатию на маску, show-close скрывает кнопку закрытия в правом верхнем углу, close-on-esc отключает закрытие по Esc, lock-scroll отключает блокировку прокрутки страницы при открытии, teleport-target задаёт контейнер монтирования.

Поведенческие переключатели
vue
<script setup lang="ts">
import { ref } from 'vue'

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

<template>
  <!-- Открыть панель «Только кнопка закрытия» -->
  <LhButton @click="adv1 = true">Только кнопка закрытия</LhButton>
  <!-- Открыть панель «Без блокировки прокрутки» -->
  <LhButton @click="adv2 = true">Без блокировки прокрутки</LhButton>
  <!-- Нажатие на маску и Esc не закрывают -->
  <LhDrawer
    v-model="adv1"
    title="Только кнопка закрытия"
    :mask-closable="false"
    :show-close="false"
    :close-on-esc="false"
  >
    <p>Нажатие на маску и Esc не закрывают панель — только кнопка.</p>
    <template #footer>
      <LhButton type="primary" @click="adv1 = false">Закрыть</LhButton>
    </template>
  </LhDrawer>
  <!-- При открытии страницу по-прежнему можно прокручивать -->
  <LhDrawer v-model="adv2" title="Без блокировки прокрутки" :lock-scroll="false">
    <p>При открытой панели страницу по-прежнему можно прокручивать.</p>
  </LhDrawer>
  <!-- Монтирование в заданный контейнер -->
  <LhDrawer v-model="adv3" title="Заданный контейнер монтирования" teleport-target="#drawer-host">
    <p>Панель перенесена в контейнер с id drawer-host.</p>
  </LhDrawer>
</template>
vue
<script>
export default {
  data() {
    return { adv1: false, adv2: false, adv3: false }
  },
}
</script>

<template>
  <!-- Открыть панель «Только кнопка закрытия» -->
  <LhButton @click="adv1 = true">Только кнопка закрытия</LhButton>
  <!-- Открыть панель «Без блокировки прокрутки» -->
  <LhButton @click="adv2 = true">Без блокировки прокрутки</LhButton>
  <!-- Нажатие на маску и Esc не закрывают -->
  <LhDrawer
    v-model="adv1"
    title="Только кнопка закрытия"
    :mask-closable="false"
    :show-close="false"
    :close-on-esc="false"
  >
    <p>Нажатие на маску и Esc не закрывают панель — только кнопка.</p>
    <template #footer>
      <LhButton type="primary" @click="adv1 = false">Закрыть</LhButton>
    </template>
  </LhDrawer>
  <!-- При открытии страницу по-прежнему можно прокручивать -->
  <LhDrawer v-model="adv2" title="Без блокировки прокрутки" :lock-scroll="false">
    <p>При открытой панели страницу по-прежнему можно прокручивать.</p>
  </LhDrawer>
  <!-- Монтирование в заданный контейнер -->
  <LhDrawer v-model="adv3" title="Заданный контейнер монтирования" teleport-target="#drawer-host">
    <p>Панель перенесена в контейнер с id drawer-host.</p>
  </LhDrawer>
</template>

Drawer API ​

Props ​

СвойствоОписаниеТипПо умолчанию
modelValueПоказывать ли (v-model)boolean—
titleЗаголовок (можно также использовать слот header)string—
directionНаправление"right" | "left" | "top" | "bottom"'right'
sizeРазмер: число — px, строка поддерживает процентыstring | number'30%'
maskClosableЗакрывать ли при нажатии на маскуbooleantrue
showCloseПоказывать ли кнопку закрытияbooleantrue
teleportTargetЦель Teleport (селектор или элемент, по умолчанию body)string | HTMLElement'body'
lockScrollБлокировать ли прокрутку страницыbooleantrue
closeOnEscЗакрывать ли по Escbooleantrue
themeVarsТематические переменные уровня компонента, переопределяют конфигурацию ConfigProvider{ [x: string]: string; }—
bgPatternФоновый узор уровня компонента, переопределяет конфигурацию ConfigProviderstring—
sxСвойство быстрой компоновки sx (применяется к панели)LhSxProps—

Events ​

СобытиеОписаниеПараметр
update:model-valueИзменение видимости(value: boolean)
openСрабатывает после открытия—
closeСрабатывает после закрытия—

Slots ​

СлотОписание
defaultОсновное содержимое
headerПользовательский заголовок (включая область заголовка)
footerПользовательская нижняя область действий

Methods ​

МетодОписание
openПрограммное открытие
closeПрограммное закрытие

Доступность ​

  • role="dialog" + aria-modal="true"; при наличии заголовка он связывается через aria-labelledby, без заголовка используется drawer.title из языкового пакета в качестве aria-label
  • При открытии фокус переносится на первый доступный для фокуса элемент панели, Tab циклически перемещается внутри панели, после закрытия фокус возвращается на триггер
  • Закрытие по Esc (можно отключить через close-on-esc); маска декоративная (aria-hidden)
  • Кнопка закрытия — настоящий <button>, aria-label берётся из языкового пакета drawer.close
  • Анимация выезда/заезда при prefers-reduced-motion упрощается до чистого плавного появления/исчезновения

Типы ​

Структура открытых TypeScript-типов этого компонента (автоматически извлечено из packages/components/drawer/src/types.ts и исходников @lh-ui/share/core/*; раскройте каждый пункт, чтобы увидеть полное определение; описания свойств — в таблице Props выше):

LhDrawerProps
ts
/**
 * Props компонента Drawer
 */
export interface LhDrawerProps {
  /** Показывать ли (v-model) */
  modelValue?: boolean
  /** Заголовок */
  title?: string
  /** Направление */
  direction?: LhDrawerDirection
  /** Размер: число — px, строка поддерживает проценты */
  size?: string | number
  /** Закрывать ли при нажатии на маску */
  maskClosable?: boolean
  /** Показывать ли кнопку закрытия */
  showClose?: boolean
  /** Цель Teleport (селектор или элемент, по умолчанию body) */
  teleportTarget?: string | HTMLElement
  /** Блокировать ли прокрутку страницы */
  lockScroll?: boolean
  /** Закрывать ли по Esc */
  closeOnEsc?: boolean
  /** Тематические переменные уровня компонента, переопределяют конфигурацию ConfigProvider */
  themeVars?: Record<string, string>
  /** Фоновый узор уровня компонента, переопределяет конфигурацию ConfigProvider */
  bgPattern?: string
  /** Свойство быстрой компоновки sx (применяется к панели) */
  sx?: LhSxProps
}
LhDrawerDirection (из @lh-ui/share/core/drawer (logic.ts))
ts
/**
 * Чистая логика Drawer (без зависимостей от фреймворка)
 */

/** Направление панели */
export type LhDrawerDirection = 'right' | 'left' | 'top' | 'bottom'

Красота традиций — основа кода