โพสต์นี้จะอธิบายพื้นฐานของการลากและวาง
สร้างเนื้อหาที่ลากได้
ในเบราว์เซอร์ส่วนใหญ่ คุณสามารถลากการเลือกข้อความ รูปภาพ และลิงก์ได้โดยค่าเริ่มต้น ตัวอย่างเช่น หากคุณลากลิงก์ลงในหน้าเว็บ คุณจะเห็นช่องเล็กๆ ที่มีไอคอน ชื่อและ URL ที่คุณสามารถวางไว้บนแถบที่อยู่หรือบนเดสก์ท็อปเพื่อสร้าง หรือไปยังลิงก์ หากต้องการทำให้เนื้อหาประเภทอื่นๆ สามารถลากได้ คุณต้องทำดังนี้ ต้องใช้ API การลากและวางของ HTML5
หากต้องการให้วัตถุลากได้ ให้ตั้งค่า draggable=true
ในองค์ประกอบนั้น ประมาณ
ทุกสิ่งที่สามารถเปิดใช้งานการลาก รวมถึงรูปภาพ ไฟล์ ลิงก์ ไฟล์ หรือ
มาร์กอัปบนหน้า
ตัวอย่างต่อไปนี้สร้างอินเทอร์เฟซเพื่อจัดเรียงคอลัมน์ที่
ด้วยตารางกริด CSS มาร์กอัปพื้นฐานสำหรับคอลัมน์จะมีลักษณะดังนี้ โดย
แอตทริบิวต์ draggable
สำหรับแต่ละคอลัมน์ที่ตั้งค่าเป็น true
:
<div class="container">
<div draggable="true" class="box">A</div>
<div draggable="true" class="box">B</div>
<div draggable="true" class="box">C</div>
</div>
นี่คือ CSS สำหรับองค์ประกอบคอนเทนเนอร์และกล่อง CSS เพียงรายเดียวที่เกี่ยวข้องกับ
ฟีเจอร์การลากคือcursor: move
โค้ดที่เหลือจะควบคุมเลย์เอาต์และการจัดรูปแบบของคอนเทนเนอร์
และกล่อง
.container {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 10px;
}
.box {
border: 3px solid #666;
background-color: #ddd;
border-radius: .5em;
padding: 10px;
cursor: move;
}
เมื่อถึงจุดนี้ คุณสามารถลากรายการได้ แต่จะไม่มีอะไรเกิดขึ้นอีก หากต้องการเพิ่ม คุณต้องใช้ JavaScript API
ฟังเหตุการณ์การลาก
หากต้องการตรวจสอบกระบวนการลาก คุณสามารถเฝ้าติดตามเหตุการณ์ใดๆ ต่อไปนี้:
ในการจัดการขั้นตอนการลาก คุณต้องมีองค์ประกอบต้นฉบับบางประเภท (ที่มีการลาก เพย์โหลดข้อมูล (สิ่งที่ถูกลาก) และเป้าหมาย (พื้นที่ที่จะ ด้วย) องค์ประกอบแหล่งที่มาเป็นองค์ประกอบได้เกือบทุกประเภท เป้าหมายคือโซนตกลงหรือชุดของโซนตกลงที่ยอมรับข้อมูลของผู้ใช้ พยายามวาง อาจมีองค์ประกอบบางอย่างเท่านั้นที่เป็นเป้าหมายได้ ตัวอย่างเช่น เป้าหมายต้องไม่ เป็นรูปภาพ
เริ่มต้นและสิ้นสุดการลากลำดับ
หลังจากกำหนดแอตทริบิวต์ draggable="true"
ในเนื้อหาแล้ว ให้แนบ
ตัวแฮนเดิลเหตุการณ์ dragstart
เพื่อเริ่มลำดับการลากสำหรับแต่ละคอลัมน์
โค้ดนี้จะตั้งค่าความทึบแสงของคอลัมน์เป็น 40% เมื่อผู้ใช้เริ่มลากคอลัมน์ แล้วปรับกลับไปเป็น 100% เมื่อเหตุการณ์การลากสิ้นสุด
function handleDragStart(e) {
this.style.opacity = '0.4';
}
function handleDragEnd(e) {
this.style.opacity = '1';
}
let items = document.querySelectorAll('.container .box');
items.forEach(function (item) {
item.addEventListener('dragstart', handleDragStart);
item.addEventListener('dragend', handleDragEnd);
});
ผลลัพธ์สามารถดูได้ในการสาธิต Glitch ต่อไปนี้ ลากรายการ และ
การเปลี่ยนแปลงความทึบแสง เนื่องจากองค์ประกอบแหล่งที่มามีเหตุการณ์ dragstart
การตั้งค่า
this.style.opacity
ถึง 40% แสดงฟีดแบ็กของผู้ใช้ว่าองค์ประกอบนั้น
การเลือกปัจจุบันที่จะย้าย เมื่อคุณวางรายการ องค์ประกอบแหล่งที่มา
กลับไปเป็นความทึบแสง 100% แม้ว่าคุณจะยังไม่ได้กำหนดลักษณะการลดลงก็ตาม
เพิ่มตัวบ่งชี้ภาพเพิ่มเติม
เพื่อช่วยให้ผู้ใช้เข้าใจวิธีโต้ตอบกับอินเทอร์เฟซของคุณ ให้ใช้
เครื่องจัดการเหตุการณ์ dragenter
, dragover
และ dragleave
ในตัวอย่างนี้
คือเป้าหมายการออกนอกเหนือจากที่ลากได้ ช่วยให้ผู้ใช้ทำสิ่งต่อไปนี้
ก็ทำความเข้าใจได้ด้วยการทำให้ขอบเป็นเส้นประเมื่อถือสิ่งที่ลากผ่าน
ตัวอย่างเช่น ใน CSS คุณอาจสร้างคลาส over
สำหรับ
องค์ประกอบที่เป็นเป้าหมายแบบเลื่อนลง:
.box.over {
border: 3px dotted #666;
}
จากนั้นตั้งค่าเครื่องจัดการเหตุการณ์ใน JavaScript และเพิ่มคลาส over
เมื่อ
วางคอลัมน์และนำออกเมื่อองค์ประกอบที่ลากออก ใน
เครื่องจัดการ dragend
เรายังจะต้องนำคลาสออกเมื่อสิ้นสุด
ลาก
document.addEventListener('DOMContentLoaded', (event) => {
function handleDragStart(e) {
this.style.opacity = '0.4';
}
function handleDragEnd(e) {
this.style.opacity = '1';
items.forEach(function (item) {
item.classList.remove('over');
});
}
function handleDragOver(e) {
e.preventDefault();
return false;
}
function handleDragEnter(e) {
this.classList.add('over');
}
function handleDragLeave(e) {
this.classList.remove('over');
}
let items = document.querySelectorAll('.container .box');
items.forEach(function(item) {
item.addEventListener('dragstart', handleDragStart);
item.addEventListener('dragover', handleDragOver);
item.addEventListener('dragenter', handleDragEnter);
item.addEventListener('dragleave', handleDragLeave);
item.addEventListener('dragend', handleDragEnd);
item.addEventListener('drop', handleDrop);
});
});
สิ่งที่ควรกล่าวถึงในโค้ดนี้มีอยู่ 2 ประการคือ
การดำเนินการเริ่มต้น สําหรับเหตุการณ์
dragover
คือการตั้งค่าพร็อพเพอร์ตี้dataTransfer.dropEffect
เป็น"none"
เราจะกล่าวถึงพร็อพเพอร์ตี้dropEffect
ในภายหลังของหน้านี้ สำหรับตอนนี้ เพิ่งรู้ว่าเหตุการณ์drop
ไม่เริ่มทำงาน หากต้องการลบล้างค่านี้ พฤติกรรม โทรหาe.preventDefault()
แนวทางปฏิบัติที่ดีอีกข้อหนึ่งคือให้กลับไปfalse
ในเครื่องจัดการเดียวกันตัวแฮนเดิลเหตุการณ์
dragenter
ใช้เพื่อสลับคลาสover
แทนdragover
หากคุณใช้dragover
เหตุการณ์จะเริ่มทำงานซ้ำๆ ขณะที่ผู้ใช้ จับรายการที่ลากไปไว้เหนือคอลัมน์ ซึ่งทำให้คลาส CSS สลับ ซ้ำๆ ซึ่งทำให้เบราว์เซอร์ทำงานที่ไม่จำเป็นจำนวนมาก ซึ่งอาจส่งผลต่อประสบการณ์ของผู้ใช้ เราแนะนำอย่างยิ่งให้ย่อ สีแดง และหากคุณต้องการใช้dragover
โปรดพิจารณา การควบคุมหรือลดระดับ Listener เหตุการณ์
เปิดตัวแอปให้เสร็จสมบูรณ์
หากต้องการประมวลผลการเปิดตัว ให้เพิ่ม Listener เหตุการณ์สำหรับเหตุการณ์ drop
ในdrop
คุณต้องป้องกันลักษณะการทำงานเริ่มต้นของเบราว์เซอร์สำหรับ การลดลง
มักจะเป็นการเปลี่ยนเส้นทางที่น่ารำคาญ หากต้องการดำเนินการนี้ โปรดโทรหา e.stopPropagation()
function handleDrop(e) {
e.stopPropagation(); // stops the browser from redirecting.
return false;
}
โปรดลงทะเบียนตัวจัดการใหม่ควบคู่ไปกับตัวจัดการอื่นๆ ดังนี้
let items = document.querySelectorAll('.container .box');
items.forEach(function(item) {
item.addEventListener('dragstart', handleDragStart);
item.addEventListener('dragover', handleDragOver);
item.addEventListener('dragenter', handleDragEnter);
item.addEventListener('dragleave', handleDragLeave);
item.addEventListener('dragend', handleDragEnd);
item.addEventListener('drop', handleDrop);
});
หากคุณเรียกใช้โค้ด ณ จุดนี้ รายการจะไม่วางไปยังตำแหน่งใหม่ ถึง
ให้ดำเนินการดังกล่าวได้ ให้ใช้ DataTransfer
ออบเจ็กต์
พร็อพเพอร์ตี้ dataTransfer
จะเก็บข้อมูลที่ส่งในการดำเนินการลาก dataTransfer
ได้รับการตั้งค่าในเหตุการณ์ dragstart
และถูกอ่านหรือจัดการในเหตุการณ์เปิดตัว การโทร
e.dataTransfer.setData(mimeType, dataPayload)
ให้คุณตั้งค่า MIME ของออบเจ็กต์
และเพย์โหลดข้อมูล
ในตัวอย่างนี้ เราจะให้ผู้ใช้เรียงลำดับคอลัมน์ใหม่ ก่อนอื่นคุณต้องจัดเก็บ HTML ขององค์ประกอบแหล่งที่มาเมื่อมีการลาก เริ่มต้น:
function handleDragStart(e) {
this.style.opacity = '0.4';
dragSrcEl = this;
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/html', this.innerHTML);
}
ในเหตุการณ์ drop
คุณจะประมวลผลการวางคอลัมน์โดยการตั้งค่าคอลัมน์แหล่งที่มา
HTML ไปยัง HTML ของคอลัมน์เป้าหมายที่คุณวางข้อมูลไว้ ช่วงเวลานี้
รวมถึงการตรวจสอบว่าผู้ใช้ไม่ได้กลับไปใช้คอลัมน์เดิม
ที่ลากมาจาก
function handleDrop(e) {
e.stopPropagation();
if (dragSrcEl !== this) {
dragSrcEl.innerHTML = this.innerHTML;
this.innerHTML = e.dataTransfer.getData('text/html');
}
return false;
}
คุณดูผลลัพธ์ได้ในการสาธิตต่อไปนี้ คุณต้องมี เบราว์เซอร์ในเดสก์ท็อป ระบบไม่รองรับ API การลากและวางบนอุปกรณ์เคลื่อนที่ ลากและ ปล่อยคอลัมน์ A ที่ด้านบนของคอลัมน์ B และสังเกตวิธีที่แต่ละตำแหน่งเปลี่ยนไป
คุณสมบัติการลากอื่นๆ
ออบเจ็กต์ dataTransfer
จะแสดงพร็อพเพอร์ตี้เพื่อแสดงฟีดแบ็กที่เป็นภาพแก่
ผู้ใช้ในระหว่างการลากและควบคุมการตอบสนองที่เป้าหมายการลดลงแต่ละรายการตอบสนองต่อ
ประเภทข้อมูลที่เฉพาะเจาะจง
dataTransfer.effectAllowed
จำกัด "ประเภทของการลาก" ที่ผู้ใช้สามารถดำเนินการในองค์ประกอบได้ ใช้ไปแล้ว ในรูปแบบการประมวลผลแบบลากและวางเพื่อเริ่มต้นdropEffect
ระหว่างdragenter
และdragover
พร็อพเพอร์ตี้สามารถมี ค่าต่อไปนี้:none
,copy
,copyLink
,copyMove
,link
,linkMove
,move
,all
และuninitialized
dataTransfer.dropEffect
ควบคุมความคิดเห็นที่ผู้ใช้จะได้รับในระหว่างdragenter
และdragover
กิจกรรม เมื่อผู้ใช้วางตัวชี้เมาส์ไว้เหนือองค์ประกอบเป้าหมาย เบราว์เซอร์ เคอร์เซอร์ระบุประเภทของการดำเนินการที่จะเกิดขึ้น เช่น คัดลอก หรือโยกย้าย เอฟเฟกต์อาจมีค่าใดค่าหนึ่งต่อไปนี้none
,copy
,link
,move
e.dataTransfer.setDragImage(imgElement, x, y)
หมายความว่าแทนที่จะใช้ 'รูปภาพผี' เริ่มต้นของเบราว์เซอร์ ความคิดเห็นของคุณ สามารถตั้งค่าไอคอนลากได้
อัปโหลดไฟล์
ตัวอย่างง่ายๆ นี้ใช้คอลัมน์เป็นทั้งแหล่งที่มาการลากและเป้าหมายการลาก ช่วงเวลานี้ อาจเกิดขึ้นใน UI ที่ขอให้ผู้ใช้จัดเรียงรายการใหม่ ในบางสถานการณ์ เป้าหมายการลากและแหล่งที่มาอาจเป็นองค์ประกอบประเภทต่างๆ กัน เช่นในอินเทอร์เฟซ ซึ่งผู้ใช้ต้องเลือกรูปภาพ 1 รูปเป็นภาพหลักสำหรับผลิตภัณฑ์ ลากรูปภาพที่เลือกไปยังเป้าหมาย
มีการใช้การลากและวางอยู่บ่อยๆ เพื่อให้ผู้ใช้ลากรายการต่างๆ จากเดสก์ท็อปไปยัง
แอปพลิเคชัน ความแตกต่างที่สำคัญอยู่ในเครื่องจัดการ drop
แทนที่จะใช้
dataTransfer.getData()
เพื่อเข้าถึงไฟล์ ข้อมูลในไฟล์จะอยู่ใน
พร็อพเพอร์ตี้ dataTransfer.files
:
function handleDrop(e) {
e.stopPropagation(); // Stops some browsers from redirecting.
e.preventDefault();
var files = e.dataTransfer.files;
for (var i = 0, f; (f = files[i]); i++) {
// Read the File objects in this FileList.
}
}
ดูข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ได้ใน การลากและวางที่กำหนดเอง