HTML5 Drag and Drop API تتيح سحب العناصر:
• draggable="true": يجعل أي عنصر قابلاً للسحب • بعض العناصر draggable بالتقصير: <a> و<img>
أهم أحداث Drag and Drop: • dragstart: بدء السحب • drag: أثناء السحب • dragend: انتهاء السحب • dragenter: الدخول لمنطقة drop • dragover: التحرك فوق منطقة drop (يحتاج preventDefault()) • dragleave: مغادرة منطقة drop • drop: الإفلات في المنطقة
DataTransfer API: • event.dataTransfer.setData(): لتعيين البيانات • event.dataTransfer.getData(): لقراءة البيانات عند Drop',
| 1 | <!-- عناصر قابلة للسحب --> |
| 2 | <div draggable="true" id="drag-item-1" class="drag-item"> |
| 3 | اسحب هذا العنصر |
| 4 | </div> |
| 5 | |
| 6 | <!-- منطقة الإفلات --> |
| 7 | <div id="drop-zone" class="drop-zone"> |
| 8 | أفلت هنا |
| 9 | </div> |
| 10 | |
| 11 | <script> |
| 12 | // بدء السحب |
| 13 | document.querySelectorAll('.drag-item').forEach(item => { |
| 14 | item.addEventListener('dragstart', (e) => { |
| 15 | e.dataTransfer.setData('text/plain', item.id); |
| 16 | e.dataTransfer.effectAllowed = 'move'; |
| 17 | item.classList.add('dragging'); |
| 18 | }); |
| 19 | |
| 20 | item.addEventListener('dragend', () => { |
| 21 | item.classList.remove('dragging'); |
| 22 | }); |
| 23 | }); |
| 24 | |
| 25 | // منطقة الإفلات |
| 26 | const dropZone = document.getElementById('drop-zone'); |
| 27 | |
| 28 | dropZone.addEventListener('dragover', (e) => { |
| 29 | e.preventDefault(); // ضروري لتفعيل drop |
| 30 | e.dataTransfer.dropEffect = 'move'; |
| 31 | dropZone.classList.add('drag-over'); |
| 32 | }); |
| 33 | |
| 34 | dropZone.addEventListener('dragleave', () => { |
| 35 | dropZone.classList.remove('drag-over'); |
| 36 | }); |
| 37 | |
| 38 | dropZone.addEventListener('drop', (e) => { |
| 39 | e.preventDefault(); |
| 40 | const draggedId = e.dataTransfer.getData('text/plain'); |
| 41 | const draggedEl = document.getElementById(draggedId); |
| 42 | dropZone.appendChild(draggedEl); |
| 43 | dropZone.classList.remove('drag-over'); |
| 44 | }); |
| 45 | </script> |
مثال 1: قائمة مهام قابلة لإعادة الترتيب
| 1 | <ul id="task-list"> |
| 2 | <li draggable="true" data-id="1">📚 تعلم HTML</li> |
| 3 | <li draggable="true" data-id="2">🎨 تعلم CSS</li> |
| 4 | <li draggable="true" data-id="3">⚡ تعلم JavaScript</li> |
| 5 | <li draggable="true" data-id="4">⚛️ تعلم React</li> |
| 6 | </ul> |
| 7 | |
| 8 | <script> |
| 9 | const list = document.getElementById('task-list'); |
| 10 | let draggedItem = null; |
| 11 | |
| 12 | list.addEventListener('dragstart', (e) => { |
| 13 | draggedItem = e.target; |
| 14 | e.target.style.opacity = '0.5'; |
| 15 | }); |
| 16 | |
| 17 | list.addEventListener('dragend', (e) => { |
| 18 | e.target.style.opacity = '1'; |
| 19 | draggedItem = null; |
| 20 | }); |
| 21 | |
| 22 | list.addEventListener('dragover', (e) => { |
| 23 | e.preventDefault(); |
| 24 | const target = e.target.closest('li'); |
| 25 | if (target && target !== draggedItem) { |
| 26 | const rect = target.getBoundingClientRect(); |
| 27 | const mid = rect.top + rect.height / 2; |
| 28 | if (e.clientY < mid) { |
| 29 | list.insertBefore(draggedItem, target); |
| 30 | } else { |
| 31 | list.insertBefore(draggedItem, target.nextSibling); |
| 32 | } |
| 33 | } |
| 34 | }); |
| 35 | </script> |