// Hàm rel, lấy ID của một đối tượng :
function rel(ob){return document.getElementById(ob);}
// Hàm getCursorPos, trả về toạ độ hiện thời của con trỏ :
var cursor = {x:0, y:0};
function getCursorPos(e) {
e = e || window.event;
if (e.pageX || e.pageY) {
cursor.x = e.pageX;
cursor.y = e.pageY;
}
else {
var de = document.documentElement;
var db = document.body;
cursor.x = e.clientX +
(de.scrollLeft || db.scrollLeft) - (de.clientLeft || 0);
cursor.y = e.clientY +
(de.scrollTop || db.scrollTop) - (de.clientTop || 0);
}
return cursor;
}
getCursorPos nhận vào một đối số e, sau đó, tuỳ theo trình duyệt khách, script tiếp theo sẽ giúp chúng ta tìm được 2 giá trị cursor.x và cursor.y. Giá trị cursor.x là khoảng cách từ con trỏ đến lề trái của trang. Còn cursor.y là khoảng cách từ con trỏ đến đỉnh trên của trang.
Bây giờ, chúng ta cùng quan sát hình ảnh sau :

Ở đây, đối tượng mà chúng ta muốn di chuyển là hình chữ nhật ABCD. Hình này nằm ở vị trí cách đỉnh trang một khoảng AX, và cách lề trái một khoảng AY.
Bắt đầu của sự di chuyển, chúng ta đưa chuột vào trong hình chữ nhật và nhấp xuống tại điểm P. Với hàm getCursorPos, chúng ta dễ dàng lấy được toạ độ của P. Chẳng hạn P cách đỉnh một khoảng pTop1, cách biên trái 1 khoảng pLeft1. Chúng ta cũng có thể xác định được khoảng cách từ P đến mỗi cạnh AB và AD :
h1=pTop1-AX ;
i1=pLeft1-AY ;
Vẫn giữ chuột như vậy, chúng ta rê đến điểm P'. Cũng bằng hàm getCursorPos, chúng ta xác định vị trí tương đối của P' so với đỉnh và lề phải của trang là pTop2 và pLeft2.
Khung chữ nhật ABCD sẽ di chuyển theo đến vị trí A'B'C'D'. Giả sử bạn nhả chuột ra tại P', việc mà chúng ta cần làm chỉ là thiết lập thuộc tính top và left cho hình chữ nhật ban đầu sao cho top = A'X' và left=A'Y'
Nhìn vào hình minh hoạ, dễ nhận thấy :
A'X' = pTop2 - h2
A'Y' = pLeft2 - i2
Mặt khác, do sự di chuyển tịnh tiến, nên i2=i1 và h2=h1 ;
Từ thực tế trên, chúng ta có ngay giải thuật để tạo ra một ứng dụng web với các đối tượng có thể kéo và thả như trên desktop.
Toàn bộ script chỉ đơn giản như dưới đây :
var dragobj=null, h1, i1, oLeft, oTop;
function makeObjectToDrag(obj){
dragobj = rel(obj.id);
document.onmousedown=startMove;
document.onmouseup = drop;
document.onmousemove = moving;
}
function startMove(e){
getCursorPos(e);
dragobj.className="moving";
i1=cursor.x- dragobj.offsetLeft;
h1=cursor.y- dragobj.offsetTop ;
}
function drop(){
if(dragobj){
dragobj.className="move";
dragobj = null;
}
}
function moving(e){
getCursorPos(e);
if(dragobj){
oLeft=cursor.x-i1;
oTop=cursor.y-h1;
dragobj.style.left = oLeft + 'px';
dragobj.style.top = oTop + 'px';
}
}
Để đưa vào trang 1 đối tượng obj1 cho phép kéo - thả, chúng ta có thể viết trong hồ sơ HTML :
<div
id="obj1"
class="move"
onmousedown="makeObjectToDrag(this);">
</div>
Khi sự kiện mousedown xảy ra trên obj1, hàm makeObjectToDrag được gọi với tham số truyền vào là bản thân đối tượng.
dòng code :
dragobj = rel(obj.id);
chỉ định các lệnh cần thực hiện tuỳ theo thao tác của người dùng :
document.onmousedown=startMove; //nhắp chuột xuống
document.onmouseup = drop; // thả chuột
document.onmousemove = moving; // di chuyển chuột
Nếu gọi hàm startMove, chúng ta lấy toạ độ con trỏ (P) và thay đổi kiểu dáng cho đối tượng để phân biệt với trạng thái bình thường. Có 2 định dạng cho đối tượng được thiết lập sẵn trong CSS :
Sau đó chúng ta tính ra các khoảng i1 và h1 theo đúng lập luận đã nêu.
Nếu chuột vẫn được kéo đi mà chưa nhả, hàm moving thực thi. Hàm này cũng bắt đầu với việc xác định vị trí con trỏ tại các điểm mà nó di chuyển qua, nghĩa là 1 tập hợp của P'. Ở mỗi điểm P' này, chúng ta thiết lập lại các giá trị định vị của đối tượng đang được kéo đi :
Khi sự kiện mouseup xảy ra, drop được gọi. Hàm này trả đối tượng về trang thái định dang ban đầu, ở vị trí mà nó được di chuyển tới.
Demo :
Và tham khảo thêm một bài viết có tựa "How to Drag and Drop in JavaScript" của tác giả Mark Kahn trên WebReference tại đây.