اذهب إلى المحتوى

السؤال

نشر

أريد أن أقوم بعمل صناديق قابلة للسحب والإفلات مثل نوافذ الويندوز على سبيل المثال، بحيث يمكنني تحريكها إلى أي مكان في الشاشة وتركها هناك.

كيف يمكني عمل هذا الأمر في المتصفح عبر JavaScript؟ بحثت عن حلول بإستخدام اللغة فقط ولكن لم أتمكن من إيجاد شرح وافي لهذا الموضوع.

Recommended Posts

  • 1
نشر

لفعل هذا يمكنك فعل التالي:

  1. أضف ال HTML:
<!-- سنجعله قابلاً للسحب DIV هنا أضفنا -->
<div id="mydiv">
  <div id="mydivheader">Click here to move</div>
  <p>Move</p>
  <p>this</p>
  <p>DIV</p>
</div>

2. أضف style كالتالي:

#mydiv {
  position: absolute;
  z-index: 9;
  background-color: #f1f1f1;
  border: 1px solid #d3d3d3;
  text-align: center;
}

#mydivheader {
  padding: 10px;
  cursor: move;
  z-index: 10;
  background-color: #2196F3;
  color: #fff;
}

وانتبه أن المهم في هذا الstyle هو ال position: absolute فقط، وبقية الخواص عدّلها براحتك.

3. أضف أكواد javascript التالية: 

dragElement(document.getElementById("mydiv"));

function dragElement(elmnt) {
  var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
  if (document.getElementById(elmnt.id + "header")) {
    // if present, the header is where you move the DIV from:
    document.getElementById(elmnt.id + "header").onmousedown = dragMouseDown;
  } else {
    // otherwise, move the DIV from anywhere inside the DIV:
    elmnt.onmousedown = dragMouseDown;
  }

  function dragMouseDown(e) {
    e = e || window.event;
    e.preventDefault();
    // get the mouse cursor position at startup:
    pos3 = e.clientX;
    pos4 = e.clientY;
    document.onmouseup = closeDragElement;
    // call a function whenever the cursor moves:
    document.onmousemove = elementDrag;
  }

  function elementDrag(e) {
    e = e || window.event;
    e.preventDefault();
    // calculate the new cursor position:
    pos1 = pos3 - e.clientX;
    pos2 = pos4 - e.clientY;
    pos3 = e.clientX;
    pos4 = e.clientY;
    // set the element's new position:
    elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
    elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
  }

  function closeDragElement() {
    // stop moving when mouse button is released:
    document.onmouseup = null;
    document.onmousemove = null;
  }
}

 

  • 1
نشر

توجد هنالك واجهة برمجية كاملة تخص السحب والافلات في جافاسكربت، تأتي بمجموعة من الأحداث يمكن بناءا عليها تحريك العناصر وفق شكل ما. نذكر:

  • drag: حدث سحب العنصر.
  • dragend: حدث نهاية سحب العنصر.
  • dragstart: حدث بداية السحب
  • drop: حدث افلات العنصر

مثلما يوجد الأحداث dragenter، dragleave و dragover

يجب اولا تعريف الخاصية draggable واسناد القيمة true لها في html . 

مثال عملي:

  • نقوم بتعريف متغير dragItem يحدد العنصر الذي يتم سحبه كل مرة. فعند سحب العنصر نقوم بتحديده عن طريق الجافاسكربت ولنعطه الصنف invisible حيث يتم تطبيق display:none على هذا العنصر، ننشئ الدالة dragStart:
    function dragStart() {
        dragItem = this;
        setTimeout(() => this.className = 'invisible', 0)
    }

    تعبر this عن العنصر المسحوب.

  • عند نهاية السحب يفترض ان تعود القيمة dragItem الى قيمتها الافتراضية. نلخص ذلك في الوظيفة dragEnd:

    function dragEnd() {
      	this.className = 'item'
      	dragItem = null;
    }

    تعبر this عن العنصر المسحوب.

  • عند الافلات يفترض ان يستقبل الحاوي الذي تم الافلات فيه العنصر المسحوب ويضيفه اليه، نلخص ذلك:

    function dragDrop() {
        this.append(dragItem);
    }

    تعبر this عن الحاوي الذي تم الافلات فيه.
    تعبر dragItem عن العنصر الذي يتم سحبه.

  • كخطوة اضافية نقوم بتعطيل الحدث dragOver لأنه يتم تشغيل هذا الحدث عند سحب الماوس فوق العنصر. وغالبا ما تكون العملية التي تحدث مماثلة لحدث السحب ونحن نستهدفها بالفعل. لنعطلها:

    function dragOver(e) {
      e.preventDefault()
    }

     

  • لنعرف الهيكلية التالية في HTML:

    <div class="container">
      <div class="column">
        <h1>اسحب من هنا</h1>
        <div class="item" draggable="true">عنصر 1</div>
        <div class="item" draggable="true">عنصر 2</div>
        <div class="item" draggable="true">عنصر 3</div>
        <div class="item" draggable="true">عنصر 4</div>
      </div>
      <div class="column">
        <h1>افلت هنا</h1>
      </div>
    </div>

     

  • نطبق التنسيقات التالية:

    .container{
        display: flex;
        gap: 30px;
    }
    .column{
        flex-basis: 20%;
        background: #ddd;
        min-height: 90vh;
        padding: 20px;
        border-radius: 10px;
    }
    .column h1{
        text-align: center;
        font-size: 22px;
    }
    .item{
        background: #fff;
        margin: 20px;
        padding: 20px;
        border-radius: 3px;
        cursor: pointer;
    }
    .invisible{
        display: none;
    }

     

  • نسند الأحداث الى الحاويات والعناصر كـ:

    const items = document.querySelectorAll('.item')
    const columns = document.querySelectorAll('.column')
    
    items.forEach(item => {
        item.addEventListener('dragstart', dragStart)
        item.addEventListener('dragend', dragEnd)
    });
    
    columns.forEach(column => {    
        column.addEventListener('dragover', dragOver);
        column.addEventListener('drop', dragDrop);
    });

     

يفترض ان يقدم هذا مقاربة بسيطة لعملية السحب والافلات عن طريق الجافاسكربت مباشرة. اختبر النتيجة هنا.

  • 1
نشر

يوجد  أحداث مدمجة في الجافاسكريبت خاصة بالسحب "dragEvent" 

يتم تشغيل حدث السحب كل بضع مئات من المللي ثانية حيث يتم سحب عنصر أو تحديد نص بواسطة المستخدم.

addEventListener('drag', (event) => {});

ondrag = (event) => { };

مثال : 

html

<div class="dropzone">
  <div id="draggable" draggable="true">
   القسم المراد سحبه
  </div>
</div>
<div class="dropzone" id="droptarget"></div>

css 

body {
/ * منع المستخدم من تحديد النص في المثال * /
  user-select: none;
}

#draggable {
  text-align: center;
  background: white;
}

.dropzone {
  width: 200px;
  height: 20px;
  background: blueviolet;
  margin: 10px;
  padding: 10px;
}

.dropzone.dragover {
  background-color: purple;
}

.dragging {
  opacity: .5;
}

javascript

let dragged;

/* تم إطلاق الأحداث على الهدف القابل للسحب */
const source = document.getElementById("draggable");
source.addEventListener("drag", (event) => {
  console.log("dragging");
});

source.addEventListener("dragstart", (event) => {
  // تخزين المرجع. على العنصر المسحوب
  dragged = event.target;
  // نجعلها نصف شفافة
  event.target.classList.add("dragging");
});

source.addEventListener("dragend", (event) => {
  //إعادة تعيين الشفافية
  event.target.classList.remove("dragging");
});

/* تم إطلاق الأحداث على  الإسقاط */
const target = document.getElementById("droptarget");
target.addEventListener("dragover", (event) => {
  // prevent default  للسماح بالإسقاط
  event.preventDefault();
}, false);

target.addEventListener("dragenter", (event) => {
  // قم بتمييز هدف الإسقاط المحتمل عند دخول العنصر القابل للسحب إليه
  if (event.target.classList.contains("dropzone")) {
    event.target.classList.add("dragover");
  }
});

target.addEventListener("dragleave", (event) => {
  // إعادة تعيين خلفية هدف الإسقاط المحتمل عندما يتركه العنصر القابل للسحب
  if (event.target.classList.contains("dropzone")) {
    event.target.classList.remove("dragover");
  }
});

target.addEventListener("drop", (event) => {
  // prevent default  (فتح كارتباط لبعض العناصر)
  event.preventDefault();
  //نقل العنصر المسحوب إلى هدف الإسقاط المحدد
  if (event.target.classList.contains("dropzone")) {
    event.target.classList.remove("dragover");
    dragged.parentNode.removeChild(dragged);
    event.target.appendChild(dragged);
  }
});

 

انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أجب على هذا السؤال...

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.

  • إعلانات

  • تابعنا على



×
×
  • أضف...