Drawer 抽屜
側滑面板,從螢幕邊緣滑入,適合比 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傳數字為 px,傳字串支援百分比(如'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 | 點選遮罩是否關閉 | boolean | true |
| showClose | 是否顯示關閉按鈕 | boolean | true |
| teleportTarget | Teleport 目標(選擇器或元素,預設 body) | string | HTMLElement | 'body' |
| lockScroll | 是否鎖定頁面捲動 | boolean | true |
| closeOnEsc | 是否回應 Esc 關閉 | boolean | true |
| themeVars | 元件級主題變數,覆寫 ConfigProvider 設定 | { [x: string]: string; } | — |
| bgPattern | 元件級背景花紋,覆寫 ConfigProvider 設定 | string | — |
| 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
/**
* Drawer 元件 Props
*/
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'