ساختن عنصر کشیدنی

ویژگی‌های وب: Pointer Events touch-action user-select

کشیدن را به عنصر شناور موجودی مثل پانل، پالت، نوارابزار، بازرس، یا کادر گفتگو اضافه کنید. کشیدن تعیین نمی‌کند که عنصر چگونه نمایش داده شود، بسته شود، روی هم قرار گیرد، یا روی آن تمرکز شود.

استفاده از نام کاربری اختصاصی

وقتی عنصر حاوی نوشتار، دکمه، ورودی، یا پیوند قابل‌انتخاب است، کشیدن را از دسته اختصاصی شروع کنید. این کار باعث می‌شود محتوای عادی آن قابل‌استفاده باقی بماند. دستگیره را برای حرکت صفحه‌کلید قابل‌تمرکز کنید و نامی دسترس‌پذیر به آن بدهید که به تعامل کلید جهت‌نما اشاره کند.

role="application" را روی دسته نمالید. تعامل فناوری کمکی را بی‌دلیل تغییر می‌دهد.

cursor: grab/grabbing، touch-action: none، و هر دو user-select: none و -webkit-user-select: none را روی دسته اعمال کنید—نه کل عنصر کشیدنی—تا نوشتار خارج از آن قابل‌انتخاب باقی بماند و اشاره‌های لمسی رفتار معمول خود را حفظ کنند:

.drag-handle {
  cursor: grab;
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
}

.drag-handle.dragging {
  cursor: grabbing;
}

حفظ موقعیت و دسترسی‌پذیری اشاره‌گر

هنگام محدود کردن حرکت به نمای پدیدار، از مدل موقعیت‌یابی مرتبط با نمای پدیدار مانند position: fixed استفاده کنید.

  • کشیدن را فقط برای دکمه اشاره‌گر اصلی (event.button === 0) شروع کنید.
  • Record the pointer offset on pointerdown and use it on every move so the element does not jump when grabbed away from its corner.
  • پس‌از اینکه اشاره‌گر دستگیره را ترک کرد، کشیدن را فعال نگه دارید. Default to setPointerCapture() and clear the dragging state on lostpointercapture. اگر ممکن است دسته در اواسط کشیدن برداشته شود یا مجدداً ارائه شود، به‌جای‌آن از شنوندگان pointermove، pointerup، و pointercancel در سطح سند استفاده کنید، زیرا در این حالت ضبط ازدست می‌رود.
  • درصورت تمایل، قبل‌از وارد شدن به حالت کشیدن، تقریباً ۴ پیکسل حرکت کنید تا کلیک کردن روی دسته باعث فعال شدن سبک کشیدن نشود.

با ضبط اشاره‌گر، شنوندگان حرکت می‌توانند روی دسته باقی بمانند:

handle.addEventListener('pointerdown', (event) => {
  if (event.button !== 0 || event.target.closest('button, input, select, textarea, a')) return;

  const rect = draggable.getBoundingClientRect();
  offsetX = event.clientX - rect.left;
  offsetY = event.clientY - rect.top;
  handle.setPointerCapture(event.pointerId);
});

handle.addEventListener('pointermove', (event) => {
  if (!handle.hasPointerCapture(event.pointerId)) return;
  handle.classList.add('dragging');
  moveTo(event.clientX - offsetX, event.clientY - offsetY);
});

handle.addEventListener('lostpointercapture', () => {
  handle.classList.remove('dragging');
});

function moveTo(left, top) {
  const maxLeft = Math.max(0, window.innerWidth - draggable.offsetWidth);
  const maxTop = Math.max(0, window.innerHeight - draggable.offsetHeight);

  draggable.style.left = `${Math.max(0, Math.min(left, maxLeft))}px`;
  draggable.style.top = `${Math.max(0, Math.min(top, maxTop))}px`;
}

هر اشاره‌گر و موقعیت صفحه‌کلید را ازطریق همان راهنما محکم کنید تا عنصر قابل‌دسترس باقی بماند. موقعیت فعلی آن را پس‌از تغییرات نمای هدف یا اندازه عنصر دوباره محدود کنید. برای عناصر با طرح‌بندی سنگین، ترجمه را درطول کشیدن درنظر بگیرید تا از طرح‌بندی هر فریم جلوگیری شود، سپس موقعیت نهایی را در left و top هنگام رها کردن اعمال کنید.

ارائه حرکت صفحه‌کلید

وقتی دسته در کانون توجه است، عنصر را با کلیدهای جهت‌نما حرکت دهید و preventDefault() را برای آن کلیدها فراخوانی کنید. از همان کمک‌کننده موقعیت‌یابی محدودشده برای حرکت اشاره‌گر استفاده کنید. افزایش ۱۵ پیکسلی نقطه شروع معقولی است؛ آن را با اندازه مؤلفه و نیازهای دقت تطبیق دهید.

یادداشت مختص کادر گفتگو

‫<dialog> یا [popover] می‌تواند از این سازوکار با سرصفحه آن به‌عنوان دسته استفاده کند. margin: 0 را قبل‌از اختصاص دادن left و top تنظیم کنید، زیرا حاشیه‌های پیش‌فرض مرورگر با موقعیت‌یابی دستی تداخل دارند. برای اطلاع از رفتار باز شدن، بسته شدن، تمرکز، و رد کردن کادر گفتگو و بالاپر، به کنترل کادر گفتگو و بالاپر اعلانی و رد کردن کادر گفتگوی کنترل‌های پلاتفرم مراجعه کنید.

راهبردهای جایگزین

وقتی کشیدن فقط جای مؤلفه را تغییر می‌دهد، آن را به‌عنوان ارتقای پیش‌رو درنظر بگیرید: بدون جاوا اسکریپت، عنصر، محتوا، و کنترل‌های آن را در موقعیت پیش‌فرض معقولی به‌صورت نمایان، خوانا، و کاربردی نگه دارید. دستگیره کشیدن غیرفعال را نمایش ندهید: اگر دستگیره یک کنترل مستقل است، آن را به‌طور پیش‌فرض پنهان کنید و هنگام مقداردهی اولیه جاوا اسکریپت نمایش دهید؛ اگر سرصفحه به‌عنوان دستگیره نیز عمل می‌کند، امکانات کشیدن آن را هنگام مقداردهی اولیه جاوا اسکریپت متصل کنید.

Include -webkit-user-select: none before user-select: none so text selection stays suppressed during dragging in Safari.