Skip to content
API 风格:

قائمة منسدلة Dropdown ​

قائمة أوامر تنبثق للأسفل. يمكن أن يكون المُشغِّل أي عنصر، وتُعرَّف عناصر القائمة عبر command، وعند النقر يُمرَّر عبر حدث command. مطبَّقة وفق نمط WAI-ARIA للقوائم: تدوير بمفاتيح الأسهم، والانتقال إلى الأول والأخير عبر Home/End، والتشغيل عبر Enter/Space، والإغلاق مع إعادة التركيز عبر Esc.

الاستخدام الأساسي ​

تشغيل بالنقر + حدث command

آخر أمر: —

vue
<template>
  <LhDropdown @command="onCommand">
    <LhButton>{{ selectedLabel || 'المزيد من العمليات' }} ▾</LhButton>
    <template #dropdown>
      <LhDropdownItem command="new">جديد</LhDropdownItem>
      <LhDropdownItem command="edit">تحرير</LhDropdownItem>
      <LhDropdownItem command="delete">حذف</LhDropdownItem>
    </template>
  </LhDropdown>
</template>

<script setup lang="ts">
import { ref } from 'vue'
const lastCommand = ref('')
// نص المُشغِّل يُدار من قبل المستخدم: لا يطرح حدث command سوى قيمة الأمر،
// ويترك طريقة عرض التصنيف للخارج
const labelMap: Record<string, string> = { new: 'جديد', edit: 'تحرير', delete: 'حذف' }
const selectedLabel = ref('')
function onCommand(command: string | number | undefined) {
  lastCommand.value = String(command)
  selectedLabel.value = labelMap[String(command)] ?? String(command)
}
</script>
vue
<script>
export default {
  data() {
    return {
      lastCommand: '',
      // نص المُشغِّل يُدار من قبل المستخدم: لا يطرح حدث command سوى قيمة الأمر،
      // ويترك طريقة عرض التصنيف للخارج
      labelMap: { new: 'جديد', edit: 'تحرير', delete: 'حذف' },
      selectedLabel: '',
    }
  },
  methods: {
    onCommand(command) {
      this.lastCommand = String(command)
      this.selectedLabel = this.labelMap[String(command)] ?? String(command)
    },
  },
}
</script>

<template>
  <LhDropdown @command="onCommand">
    <LhButton>{{ selectedLabel || 'المزيد من العمليات' }} ▾</LhButton>
    <template #dropdown>
      <LhDropdownItem command="new">جديد</LhDropdownItem>
      <LhDropdownItem command="edit">تحرير</LhDropdownItem>
      <LhDropdownItem command="delete">حذف</LhDropdownItem>
    </template>
  </LhDropdown>
</template>

طريقة التشغيل ​

الافتراضي هو click، ويمكن أيضًا التغيير إلى التمرير بالفأرة أو زر الفأرة الأيمن.

hover / contextmenu
vue
<script setup lang="ts">
import { ref } from 'vue'
const hoverLabel = ref('')
function onHoverCommand(command: string | number | undefined) {
  hoverLabel.value = String(command)
}
const contextLabel = ref('')
function onContextCommand(command: string | number | undefined) {
  contextLabel.value = String(command)
}
</script>

<template>
  <!-- تشغيل بالتمرير -->
  <LhDropdown trigger="hover" @command="onHoverCommand">
    <LhButton>{{ hoverLabel || 'تشغيل بالتمرير' }} ▾</LhButton>
    <template #dropdown>
      <LhDropdownItem command="hover-1">الخيار الأول</LhDropdownItem>
      <LhDropdownItem command="hover-2">الخيار الثاني</LhDropdownItem>
    </template>
  </LhDropdown>
  <!-- تشغيل بزر الفأرة الأيمن -->
  <LhDropdown trigger="contextmenu" @command="onContextCommand">
    <LhButton>{{ contextLabel || 'تشغيل بزر الفأرة الأيمن' }} ▾</LhButton>
    <template #dropdown>
      <LhDropdownItem command="ctx-1">تحديث</LhDropdownItem>
      <LhDropdownItem command="ctx-2">نسخ</LhDropdownItem>
    </template>
  </LhDropdown>
</template>
vue
<script>
export default {
  data() {
    return { hoverLabel: '', contextLabel: '' }
  },
  methods: {
    onHoverCommand(command) {
      this.hoverLabel = String(command)
    },
    onContextCommand(command) {
      this.contextLabel = String(command)
    },
  },
}
</script>

<template>
  <!-- تشغيل بالتمرير -->
  <LhDropdown trigger="hover" @command="onHoverCommand">
    <LhButton>{{ hoverLabel || 'تشغيل بالتمرير' }} ▾</LhButton>
    <template #dropdown>
      <LhDropdownItem command="hover-1">الخيار الأول</LhDropdownItem>
      <LhDropdownItem command="hover-2">الخيار الثاني</LhDropdownItem>
    </template>
  </LhDropdown>
  <!-- تشغيل بزر الفأرة الأيمن -->
  <LhDropdown trigger="contextmenu" @command="onContextCommand">
    <LhButton>{{ contextLabel || 'تشغيل بزر الفأرة الأيمن' }} ▾</LhButton>
    <template #dropdown>
      <LhDropdownItem command="ctx-1">تحديث</LhDropdownItem>
      <LhDropdownItem command="ctx-2">نسخ</LhDropdownItem>
    </template>
  </LhDropdown>
</template>

التشغيل عبر contextmenu يمنع القائمة السياقية الافتراضية للمتصفح.

التعطيل والفاصل ​

disabled / divided
vue
<script setup lang="ts">
import { ref } from 'vue'
const actionLabel = ref('')
function onActionCommand(command: string | number | undefined) {
  actionLabel.value = String(command)
}
</script>

<template>
  <!-- قائمة عمليات مع عنصر معطّل وفاصل -->
  <LhDropdown @command="onActionCommand">
    <LhButton>{{ actionLabel || 'عملية' }} ▾</LhButton>
    <template #dropdown>
      <LhDropdownItem command="export">تصدير</LhDropdownItem>
      <LhDropdownItem command="import">استيراد</LhDropdownItem>
      <LhDropdownItem divided command="audit">سجل التدقيق</LhDropdownItem>
      <LhDropdownItem disabled command="purge">تفريغ البيانات</LhDropdownItem>
    </template>
  </LhDropdown>
</template>
vue
<script>
export default {
  data() {
    return { actionLabel: '' }
  },
  methods: {
    onActionCommand(command) {
      this.actionLabel = String(command)
    },
  },
}
</script>

<template>
  <!-- قائمة عمليات مع عنصر معطّل وفاصل -->
  <LhDropdown @command="onActionCommand">
    <LhButton>{{ actionLabel || 'عملية' }} ▾</LhButton>
    <template #dropdown>
      <LhDropdownItem command="export">تصدير</LhDropdownItem>
      <LhDropdownItem command="import">استيراد</LhDropdownItem>
      <LhDropdownItem divided command="audit">سجل التدقيق</LhDropdownItem>
      <LhDropdownItem disabled command="purge">تفريغ البيانات</LhDropdownItem>
    </template>
  </LhDropdown>
</template>

يبقى العنصر المعطّل قابلًا للتركيز (aria-disabled="true")، فيتمكن قارئ الشاشة من قراءته؛ لكن مفاتيح الأسهم تتخطاه، ولا يُطلق النقر ولا Enter/Space حدث command.

الموضع والارتفاع الأقصى ​

placement و maxHeight
vue
<script setup lang="ts">
import { ref } from 'vue'
const itemLabel = ref('')
function onItemCommand(command: string | number | undefined) {
  itemLabel.value = `العنصر ${command}`
}
</script>

<template>
  <!-- أسفل مع محاذاة الطرف وتقييد الارتفاع الأقصى -->
  <LhDropdown placement="bottom-end" :max-height="160" @command="onItemCommand">
    <LhButton>{{ itemLabel || 'أسفل مع محاذاة الطرف' }} ▾</LhButton>
    <template #dropdown>
      <LhDropdownItem v-for="i in 12" :key="i" :command="i">العنصر {{ i }}</LhDropdownItem>
    </template>
  </LhDropdown>
</template>
vue
<script>
export default {
  data() {
    return { itemLabel: '' }
  },
  methods: {
    onItemCommand(command) {
      this.itemLabel = `العنصر ${command}`
    },
  },
}
</script>

<template>
  <!-- أسفل مع محاذاة الطرف وتقييد الارتفاع الأقصى -->
  <LhDropdown placement="bottom-end" :max-height="160" @command="onItemCommand">
    <LhButton>{{ itemLabel || 'أسفل مع محاذاة الطرف' }} ▾</LhButton>
    <template #dropdown>
      <LhDropdownItem v-for="i in 12" :key="i" :command="i">العنصر {{ i }}</LhDropdownItem>
    </template>
  </LhDropdown>
</template>

التحكم الظاهر والإخفاء وسلوك النقر ​

يتحكم v-model:visible يدويًا في الظهور والإخفاء؛ ويتحكم hide-on-click فيما إذا كانت القائمة تُطوى تلقائيًا بعد الاختيار؛ ويضيف popper-class صنفًا مخصصًا للطبقة المنبثقة؛ ويحدد teleport-target حاوية التركيب.

التحكم الظاهر والإخفاء
vue
<script setup lang="ts">
import { ref } from 'vue'
const menuVisible = ref(false)
</script>

<template>
  <!-- تحكم ظاهر وإخفاء: لا يُطوى بعد الاختيار -->
  <LhDropdown
    v-model:visible="menuVisible"
    :hide-on-click="false"
    popper-class="demo-dropdown-popper"
  >
    <LhButton>{{ menuVisible ? 'طي' : 'عرض' }} ▾</LhButton>
    <template #dropdown>
      <LhDropdownItem command="copy">نسخ (لا يُطوى بعد الاختيار)</LhDropdownItem>
      <LhDropdownItem command="paste">لصق</LhDropdownItem>
    </template>
  </LhDropdown>
</template>
vue
<script>
export default {
  data() {
    return { menuVisible: false }
  },
}
</script>

<template>
  <!-- تحكم ظاهر وإخفاء: لا يُطوى بعد الاختيار -->
  <LhDropdown
    v-model:visible="menuVisible"
    :hide-on-click="false"
    popper-class="demo-dropdown-popper"
  >
    <LhButton>{{ menuVisible ? 'طي' : 'عرض' }} ▾</LhButton>
    <template #dropdown>
      <LhDropdownItem command="copy">نسخ (لا يُطوى بعد الاختيار)</LhDropdownItem>
      <LhDropdownItem command="paste">لصق</LhDropdownItem>
    </template>
  </LhDropdown>
</template>
التركيب في حاوية محددة
vue
<script setup lang="ts">
</script>

<template>
  <!-- التركيب في حاوية محددة -->
  <LhDropdown teleport-target="#dropdown-zone">
    <LhButton>المزيد ▾</LhButton>
    <template #dropdown>
      <LhDropdownItem command="a">خيار</LhDropdownItem>
    </template>
  </LhDropdown>
</template>
vue
<script>
export default {}
</script>

<template>
  <!-- التركيب في حاوية محددة -->
  <LhDropdown teleport-target="#dropdown-zone">
    <LhButton>المزيد ▾</LhButton>
    <template #dropdown>
      <LhDropdownItem command="a">خيار</LhDropdownItem>
    </template>
  </LhDropdown>
</template>

واجهة برمجة تطبيقات Dropdown ​

الخصائص ​

الخاصيةالوصفالنوعالافتراضي
triggerطريقة التشغيل"hover" | "click" | "contextmenu"'click'
placementموضع العرض (12 موضعًا، مماثلة لـ Tooltip)"top" | "top-start" | "top-end" | "bottom" | "bottom-start" | "bottom-end" | "left" | "left-start" | "left-end" | "right" | "right-start" | "right-end"'bottom-start'
visibleحالة الظهور (v-model:visible)boolean—
disabledما إذا كان المُشغِّل معطّلًاboolean—
hideOnClickما إذا كانت القائمة تُغلق تلقائيًا بعد النقر على عنصرbooleantrue
teleportTargetوجهة Teleport (محدِّد أو عنصر)string | HTMLElement'body'
popperClassاسم الصنف المخصص للطبقة المنبثقةstring—
maxHeightالارتفاع الأقصى للقائمة (رقم يعني px)string | number—
themeVarsمتغيرات السمة على مستوى المكوّن{ [x: string]: string; }—
bgPatternنمط الخلفية على مستوى المكوّن، يتجاوز إعدادات ConfigProviderstring—
sxخصائص التخطيط السريع sx (تُطبَّق على العنصر الجذري للمُشغِّل)LhSxProps—

الأحداث ​

الحدثالوصفالمعاملات
commandيُطلق عند النقر على عنصر في القائمة(command: string | number | undefined)
clickيُطلق عند النقر على عنصر القائمة (LhDropdownItem)(command: string | number | undefined)
visible-changeتغيّر الظهور والإخفاء(value: boolean)
update:visibleتغيّر الظهور والإخفاء (v-model)(value: boolean)

الفتحات ​

الفتحةالوصف
defaultمحتوى المُشغِّل
dropdownمحتوى القائمة (قائمة LhDropdownItem)

التوابع ​

التابعالوصف
showعرض برمجي
hideطي برمجي
toggleتبديل برمجي

واجهة برمجة تطبيقات DropdownItem ​

الخصائص ​

الخاصيةالوصفالنوعالافتراضي
commandمُعرِّف الأمر، يُطرف مع حدث command عند النقرstring | number—
disabledما إذا كان معطّلًاbooleanfalse
dividedما إذا كان يُعرض فاصل فوقهbooleanfalse

إمكانية الوصول ​

  • يحمل المُشغِّل aria-haspopup="menu" وaria-expanded؛ والقائمة role="menu"، وعناصرها role="menuitem"
  • تتبع لوحة المفاتيح نمط APG للقوائم: ↑/↓ بالتدوير (مع تخطّي العناصر المعطّلة)، وHome/End للانتقال إلى الأول والأخير، وEnter/Space لإطلاق command والإغلاق، وEsc للإغلاق وإعادة التركيز
  • تستخدم العناصر المعطّلة aria-disabled بدلًا من إزالتها من شجرة التركيز، ويتخطاها كل من مفاتيح الأسهم ومفتاح الإدخال
  • عند تجاوز القائمة المنبثقة للمحور الرئيسي ينعكس الاتجاه تلقائيًا، وعند تجاوزها للمحور المتقاطع تُرَدّ إلى إطار العرض

تعريفات الأنواع ​

بنى TypeScript التي يصدّرها هذا المكوّن خارجيًا (مستخرَجة تلقائيًا من packages/components/dropdown/src/types.ts و@lh-ui/share/core/*؛ انقر كل عنصر لعرض التعريف كاملًا؛ وصف الخصائص في جدول الخصائص أعلاه):

LhDropdownProps
ts
/**
 * خاصيات مكوّن Dropdown
 */
export interface LhDropdownProps {
  /** طريقة التشغيل */
  trigger?: LhDropdownTrigger
  /** موضع العرض */
  placement?: LhDropdownPlacement
  /** حالة العرض المُدارة يدويًا (v-model:visible) */
  visible?: boolean
  /** ما إذا كان معطّلًا */
  disabled?: boolean
  /** ما إذا كانت القائمة تُغلق تلقائيًا بعد النقر على عنصر */
  hideOnClick?: boolean
  /** وجهة Teleport (محدِّد أو عنصر، الافتراضي body) */
  teleportTarget?: string | HTMLElement
  /** اسم الصنف المخصص للطبقة المنبثقة */
  popperClass?: string
  /** الارتفاع الأقصى للقائمة */
  maxHeight?: string | number
  /** متغيرات السمة على مستوى المكوّن، تتجاوز إعدادات ConfigProvider */
  themeVars?: Record<string, string>
  /** نمط الخلفية على مستوى المكوّن، يتجاوز إعدادات ConfigProvider */
  bgPattern?: string
  /** خصائص التخطيط السريع sx (تُطبَّق على العنصر الجذري للمُشغِّل) */
  sx?: LhSxProps
}
LhDropdownItemProps
ts
/**
 * خاصيات مكوّن DropdownItem
 */
export interface LhDropdownItemProps {
  /** مُعرِّف الأمر، يُطرف مع حدث command عند النقر */
  command?: string | number
  /** ما إذا كان معطّلًا (تبقى قابلية التركيز للدخول في شجرة إمكانية الوصول) */
  disabled?: boolean
  /** ما إذا كان يُعرض فاصل */
  divided?: boolean
}
LhDropdownTrigger (مأخوذ من @lh-ui/share/core/dropdown (logic.ts))
ts
/** طريقة التشغيل */
export type LhDropdownTrigger = 'hover' | 'click' | 'contextmenu'

جمال التقاليد، أساس الكود