Modal
کامپوننت دیالوگ برای تعاملهای متمرکز روی صفحه جاری، همراه با بهدامانداختن فوکوس، قفل اسکرول و بیاثر کردن پسزمینه.
کجا به کار میآید: وقتی به دیالوگی برای یک تعامل متمرکز روی صفحه نیاز دارید، با بهدامانداختن فوکوس، قفل اسکرول و بیاثر کردن پسزمینه.
<r-modal>را با اتریبیوتopenیا با کمککنندههای دستوریModal.confirm/Modal.infoبگردانید.
شروع سریع
کاربرد پایه
دیدهشدن مودال را اتریبیوت open (یا ویژگی open) تعیین میکند. در آغاز بسته است و تا باز نشود چیزی رسم نمیکند، پس یک محرک برای باز و بسته کردنش سیمکشی کنید.
این محتوای مودال است.
<r-button onclick="modal.open = true">باز کردن مودال</r-button>
<r-modal id="modal" heading="مودال پایه">
<p>این محتوای مودال است.</p>
<div slot="footer">
<r-button type="primary" onclick="modal.open = false">تأیید</r-button>
</div>
</r-modal>مرجع API
ویژگیها
| ویژگی | نوع | پیشفرض | توضیح |
|---|---|---|---|
open | boolean | false | اینکه مودال دیده میشود یا نه |
heading | string | '' | متن عنوان سربرگ (وقتی خالی باشد به Modal برمیگردد) |
closable | boolean | true | اینکه دکمه بستن (x) نمایش داده شود یا نه |
maskClosable | boolean | true | اینکه کلیک روی ماسک پسزمینه مودال را ببندد یا نه |
closeOnEsc | boolean | true | اینکه فشردن Escape مودال را ببندد یا نه |
lockScroll | boolean | true | اینکه تا وقتی مودال باز است اسکرول body قفل شود یا نه |
autoFocus | boolean | true | اینکه هنگام باز شدن، اولین عنصر فوکوسپذیر فوکوس بگیرد یا نه |
hideHeader | boolean | false | نوار عنوان را یکسره حذف میکند و فقط یک دکمه بستن شناور میماند |
sheet | string | '' | CSSی که به Shadow DOM تزریق میشود |
closing یک اتریبیوت فقطخواندنی است که عنصر روی خودش بازتاب میدهد (نه ویژگیای که بشود مقدار داد): از همان لحظهای که close() اجرا میشود تا وقتی گذارِ محوشدن و کوچکشدنِ ماسک و دیالوگ واقعاً تمام شود حاضر است (حدود ۰٫۳ ثانیه بعد، همزمان با رویداد afterclose). برای صفحه میزبانی مفید است که لازم دارد در طول آن دنباله بصری هم مودال همچنان «حاضر» شمرده شود؛ بهترین شیوهها در پایین را ببینید.
عنوان title
<r-modal open heading="حذف مورد">
<p>مطمئنید که میخواهید این مورد را حذف کنید؟</p>
</r-modal>دکمه بستن closable
دکمه بستن سربرگ را پنهان میکند تا مودال فقط از راه کنترلهای خودتان بسته شود.
<r-modal open heading="شرایط" closable="false">
<p>برای ادامه باید شرایط را بپذیرید.</p>
<div slot="footer">
<r-button type="primary">میپذیرم</r-button>
</div>
</r-modal>بستن با ماسک maskClosable
بهطور پیشفرض کلیک روی پسزمینه مودال را میبندد. با false میتوانید یک کنش صریح را الزامی کنید.
<r-modal open heading="تغییرات ذخیرهنشده" maskClosable="false">
<p>کلیک بیرون، این دیالوگ را نمیبندد.</p>
</r-modal>بستن با Escape closeOnEsc
<r-modal open heading="گزارش" closeOnEsc="false">
<p>کلید Escape برای این دیالوگ غیرفعال است.</p>
</r-modal>قفل اسکرول lockScroll
<r-modal open heading="پیشنمایش" lockScroll="false">
<p>صفحه پشت مودال همچنان اسکرول میشود.</p>
</r-modal>فوکوس خودکار autoFocus
<r-modal open heading="جستجو" autoFocus="false">
<input type="text" placeholder="برای جستجو تایپ کنید" />
</r-modal>حالت بدون سربرگ hideHeader
نوار عنوان و خط جداکنندهاش را یکسره حذف میکند و وقتی closable باشد فقط یک دکمه بستن شناور (بالا-راست) میماند. مناسبِ دیالوگهایی که فقط محتوا هستند، مثل لایتباکس تصویر یا نمودار، که نوار عنوان در آنها جز خوردن فضای محتوا کاری نمیکند. دیالوگ حتی بدون عنوان دیدنیِ <h3> هم نام دسترسپذیرش را از aria-label (برگرفته از title) نگه میدارد، پس در این حالت هم title را برای برچسب صفحهخوان تنظیم کنید.
<r-modal open hide-header>
<img src="/diagram.png" alt="نمودار معماری" style="display: block; max-width: 100%;" />
</r-modal>اسلاتها
| اسلات | توضیح |
|---|---|
| (پیشفرض) | محتوای بدنه مودال |
footer | کنشهای پاورقی؛ نوار پاورقی فقط وقتی پر باشد دیده میشود |
<r-modal open heading="تأیید">
<p>محتوای بدنه در اسلات پیشفرض مینشیند.</p>
<div slot="footer">
<r-button onclick="modal.open = false">انصراف</r-button>
<r-button type="primary">تأیید</r-button>
</div>
</r-modal>رویدادها
همه رویدادهای مربوط به بستهشدن، در event.detail یک trigger دارند که میگوید چه چیزی باعث بسته شدن شده است: 'mask'، 'button'، 'escape' یا 'program'.
| رویداد | لغوپذیر | detail | توضیح |
|---|---|---|---|
beforeopen | بله | — | پیش از باز شدن؛ برای لغو preventDefault() را صدا بزنید |
open | خیر | — | وقتی مودال باز میشود |
afteropen | خیر | — | پس از پایان گذار باز شدن |
beforeclose | بله | { trigger } | پیش از بسته شدن؛ برای لغو preventDefault() را صدا بزنید |
close | خیر | { trigger } | وقتی مودال بسته میشود |
afterclose | خیر | { trigger } | پس از پایان گذار بسته شدن |
<r-modal id="modal" heading="نمونه"></r-modal>
<script>
const modal = document.getElementById('modal');
modal.addEventListener('beforeclose', (e) => {
if (!confirm('تغییرات دور ریخته شود؟')) e.preventDefault();
});
modal.addEventListener('close', (e) => {
console.log('بسته شد از راه', e.detail.trigger); // 'mask' | 'button' | 'escape' | 'program'
});
</script>API برنامهنویسی
کلاس Modal کمککنندههای استاتیکی دارد که بدون هیچ مارکآپی یک مودال میسازند، سوار میکنند و نتیجهاش را برمیگردانند. هرکدام یک Promise<{ action, trigger }> میدهند که در آن action یکی از 'confirm'، 'cancel' یا 'dismiss' است.
| متد | توضیح |
|---|---|
Modal.open(opts) | باز کردن مودالی با یک دکمه تأیید |
Modal.confirm(opts) | باز کردن مودالی با دکمههای تأیید و انصراف |
Modal.info(opts) | مودال اطلاعرسانی (عنوان پیشفرض Info) |
Modal.success(opts) | مودال موفقیت (عنوان پیشفرض Success) |
Modal.warning(opts) | مودال هشدار (عنوان پیشفرض Warning) |
Modal.error(opts) | مودال خطا (عنوان پیشفرض Error) |
گزینهها (همه اختیاری): title، content، okText، cancelText، showCancel، maskClosable، closeOnEsc، lockScroll، autoFocus، closable، onConfirm، onCancel. اگر onConfirm / onCancel مقدار false (یا پرامیسی که به false میرسد) برگردانند، مودال باز میماند.
import { Modal } from 'ranui/modal';
const result = await Modal.confirm({
title: 'حذف پروژه',
content: 'این کار برگشتپذیر نیست.',
okText: 'حذف',
cancelText: 'نگهداشتن',
onConfirm: async () => {
await deleteProject();
},
});
if (result.action === 'confirm') {
// حذف شد
}Partهای CSS
قطعههای درونی را با ::part() استایل بدهید.
| Part | توضیح |
|---|---|
root | ظرف بیرونی لایه پوششی |
mask | پسزمینه پشت دیالوگ |
dialog | خودِ جعبه دیالوگ |
header | نوار سربرگ |
title | تیتر عنوان |
close | دکمه بستن (x) |
body | ناحیه بدنه با قابلیت اسکرول |
footer | نوار کنشهای پاورقی |
r-modal::part(dialog) {
border-radius: 8px;
}
r-modal::part(mask) {
background: rgba(0, 0, 0, 0.6);
}استایلدهی
<r-modal> ۲۳ ویژگی سفارشی CSS از آنِ خود دارد، بهعلاوه توکنهای معنایی که از پوسته میخواند. هر جا که ارث برسد میتوانید یکی را تعیین کنید: :root، یک دربرگیرنده، یا خود عنصر:
r-modal {
--ran-modal-mask-background: var(--ran-color-bg-subtle);
}Partها: body · close · dialog · footer · header · mask · root · title
فهرست کامل در توکنهای استایل است؛ اینکه کدام توکن را به کار ببرید در سیستم طراحی آمده.
بهترین شیوهها
- محرک و جابهجایی: با
modal.open = trueباز کنید و باmodal.open = falseببندید، یاclose()را صدا بزنید. - جلوی بستنهای ویرانگر را بگیرید: به
beforecloseگوش دهید و باpreventDefault()پیش از دور ریختن کار ذخیرهنشده تأیید بگیرید. - کنشهای پاورقی: دکمههای اصلی و فرعی را در
slot="footer"بگذارید؛ نوار پاورقی فقط وقتی اسلات محتوا داشته باشد ظاهر میشود. - جریانهای بیراهفرار: با
closable="false"وmaskClosable="false"انتخاب صریح را الزامی کنید. - دیالوگهای یکبارمصرف: برای پرسشهای سریع بهجای نوشتن مارکآپ از
Modal.confirm/Modal.infoاستفاده کنید. - بالا بردن صفحه میزبان روی مودالِ باز: به
:has(r-modal[open]), :has(r-modal[closing])تطبیق دهید، نه فقط[open].openهمان لحظهای کهclose()اجرا میشود برداشته میشود، اما گذار ماسک و دیالوگ حدود ۰٫۳ ثانیه دیگر هم رسم میشود؛ اگر ارتقای z-index را وسط محو شدن رها کنید، ماسکِ هنوز دیدنی زیر همان چیزی که رویش برده بودید دوباره رسم میشود.