درج Drawer
لوحة تنزلق من حافة الشاشة، تناسب العمليات المؤقتة الأقرب إلى الحافة مما هي عليه في Dialog (التفاصيل، التصفية، خطوات المعالج). مثل Dialog تستخدم role="dialog" + aria-modal="true"، ويبقى التركيز داخل اللوحة، ويمكن الإغلاق عبر Esc أو النقر على الطبقة المعتمة.
الاستخدام الأساسي
<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><script>
export default {
data() {
return { basic: false }
},
}
</script>
<template>
<LhButton @click="basic = true">فتح الدرج</LhButton>
<LhDrawer v-model="basic" title="تفاصيل الطلب">
<p>يُوضع هنا المحتوى الرئيسي للدرج.</p>
</LhDrawer>
</template>أربع جهات
<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><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>حجم مخصص وقسم سفلي
<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><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 تحدد حاوية التركيب.
<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>نُقلت اللوحة إلى الحاوية ذات المعرّف drawer-host.</p>
</LhDrawer>
</template><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>نُقلت اللوحة إلى الحاوية ذات المعرّف drawer-host.</p>
</LhDrawer>
</template>واجهة برمجة تطبيقات Drawer
الخصائص
| الخاصية | الوصف | النوع | الافتراضي |
|---|---|---|---|
| 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 | — |
الأحداث
| الحدث | الوصف | المعاملات |
|---|---|---|
| update:model-value | تغيّر الظهور والإخفاء | (value: boolean) |
| open | يُطلق بعد الفتح | — |
| close | يُطلق بعد الإغلاق | — |
الفتحات
| الفتحة | الوصف |
|---|---|
| default | المحتوى الرئيسي |
| header | ترويسة مخصصة (تشمل منطقة العنوان) |
| footer | منطقة العمليات السفلية مخصصة |
التوابع
| التابع | الوصف |
|---|---|
| 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/*؛ انقر كل عنصر لعرض التعريف كاملًا؛ وصف الخصائص في جدول الخصائص أعلاه):
LhDrawerProps
/**
* خاصيات مكوّن 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))
/**
* منطق Drawer الدوالي البحت (بلا اعتماد على إطار عمل)
*/
/** جهة الدرج */
export type LhDrawerDirection = 'right' | 'left' | 'top' | 'bottom'