實作成果示範
物件拖曳的重點在於物件位置的計算公式 - 目前滑鼠位置-起始滑鼠位置+目標位置
單純拖曳物件的話不算困難
說的上比較困難的是拖曳之後要結合的動作(如:drop、sortable list等)
雖然HTML5有Drag相關的API,不過這邊就先不提了
先做出一個能相容於老舊瀏覽器(IE)的版本
GitHub檔案目錄
首先實作一個專門用來記錄位置的類別
物件的函式結果回傳位置本身,這樣寫主要是方便連綴的使用方法
function Position(x, y) {
this.X = x ? x : 0;
this.Y = y ? y : 0;
this.add = function (val) {
if (val) {
if (!isNaN(val.X)) this.X += val.X;
if (!isNaN(val.Y)) this.Y += val.Y;
}
return this;
};
this.subtract = function (val) {
if (val) {
if (!isNaN(val.X)) this.X -= val.X;
if (!isNaN(val.Y)) this.Y -= val.Y;
}
return this;
};
this.min = function (val) {
if (!val) return this;
if (!isNaN(val.X)) this.X = Math.min(this.X, val.X);
if (!isNaN(val.Y)) this.Y = Math.min(this.Y, val.Y);
return this;
};
this.max = function (val) {
if (!val) return this;
if (!isNaN(val.X)) this.X = Math.max(this.X, val.X);
if (!isNaN(val.Y)) this.Y = Math.max(this.Y, val.Y);
return this;
};
this.apply = function (element, control) {
if (!element) return;
if (!isNaN(this.X)) {
if (!control || !(control.orientation != 'horizontal' || (control.upperLimit && this.X > control.upperLimit)
|| (control.lowerLimit && this.X < control.lowerLimit)))
element.style.left = this.X + 'px';
}
if (!isNaN(this.Y)) {
if (!control || !(control.orientation != 'vertical' || (control.upperLimit && this.Y > control.upperLimit)
|| (control.lowerLimit && this.Y < control.lowerLimit)))
element.style.top = this.Y + 'px';
}
};
}
接著撰寫一個取得現在滑鼠位置的method
function absoluteCursorPosition(e) {
e = e || window.event;
if (isNaN(window.scrollX))
return new Position(e.clientX + document.documentElement.scrollLeft + document.body.scrollLeft,
e.clientY + document.documentElement.scrollTop + document.body.scrollTop);
else
return new Position(e.clientX + window.scrollX, e.clientY + window.scrollY);
}
最後重點來了,實作拖曳物件的類別
裡頭包含了紀錄之前滑鼠位置與物件起始位置的類別成員
使用dragging當指標控管拖曳行為的發生
避免因滑鼠移動到別的拖曳物件上造成預期外的行為
另提供3個使用callback function的機會,如果要設計拖曳後的行為便是利用這裡設計
稍微注意一下 dragGo 事件是綁在document上
這是要避免滑鼠移太快而讓物件自身的 onmousemove 事件沒有繼續被觸發
function dragObject(element, startCallback, moveCallback, endCallback) {
if (!element) return;
var cursorStartPos, elementClientRect, elementStartPos;
var dragging = false;
var control;
if (document.addEventListener) element.addEventListener("mousedown", dragStart, false);
else element.attachEvent("onmousedown", dragStart);
function dragStart(e) {
e = e || window.event;
if ((e.which && e.which != 1) || (e.button && e.button != 1)) return; //only allow mouse left key
if (dragging) return;
dragging = true;
if (startCallback) control = startCallback(e, element);
cursorStartPos = absoluteCursorPosition(e);
elementClientRect = element.getBoundingClientRect();
elementStartPos = new Position(elementClientRect.left - element.parentNode.scrollLeft, parseInt(element.style.top));
if (document.addEventListener) {
document.addEventListener("mousemove", dragGo, false);
document.addEventListener("mouseup", dragStop, false);
} else {
document.attachEvent("onmousemove", dragGo);
document.attachEvent("onmouseup", dragStop);
}
}
function dragGo(e) {
if (!dragging) return;
absoluteCursorPosition(e).add(elementStartPos).subtract(cursorStartPos).apply(element, control);
if (moveCallback) moveCallback(e, element);
}
function dragStop(e) {
if (!dragging) return;
dragging = false;
cursorStartPos = null;
elementStartPos = null;
if (endCallback) endCallback(e, element);
if (document.removeEventListener) {
document.removeEventListener("mousemove", dragGo, false);
document.removeEventListener("mouseup", dragStop, false);
} else {
document.detachEvent("onmousemove", dragGo);
document.detachEvent("onmouseup", dragStop);
}
}
this.dispose = function () {
if (element.removeEventListener) element.removeEventListener("mousedown", dragStart, false);
else element.detachEvent("onmousedown", dragStart);
};
}
完整程式範例請至這裡
要取消已設定可拖曳的元件的拖曳行為,可以再呼叫dispose
//after drag action is over, remove it
dothis.dispose();
實務上也常搭配 z-index 使用,請視情況自行設計
物件拖曳的重點在於物件位置的計算公式 - 目前滑鼠位置-起始滑鼠位置+目標位置
單純拖曳物件的話不算困難
說的上比較困難的是拖曳之後要結合的動作(如:drop、sortable list等)
雖然HTML5有Drag相關的API,不過這邊就先不提了
先做出一個能相容於老舊瀏覽器(IE)的版本
GitHub檔案目錄
首先實作一個專門用來記錄位置的類別
物件的函式結果回傳位置本身,這樣寫主要是方便連綴的使用方法
function Position(x, y) {
this.X = x ? x : 0;
this.Y = y ? y : 0;
this.add = function (val) {
if (val) {
if (!isNaN(val.X)) this.X += val.X;
if (!isNaN(val.Y)) this.Y += val.Y;
}
return this;
};
this.subtract = function (val) {
if (val) {
if (!isNaN(val.X)) this.X -= val.X;
if (!isNaN(val.Y)) this.Y -= val.Y;
}
return this;
};
this.min = function (val) {
if (!val) return this;
if (!isNaN(val.X)) this.X = Math.min(this.X, val.X);
if (!isNaN(val.Y)) this.Y = Math.min(this.Y, val.Y);
return this;
};
this.max = function (val) {
if (!val) return this;
if (!isNaN(val.X)) this.X = Math.max(this.X, val.X);
if (!isNaN(val.Y)) this.Y = Math.max(this.Y, val.Y);
return this;
};
this.apply = function (element, control) {
if (!element) return;
if (!isNaN(this.X)) {
if (!control || !(control.orientation != 'horizontal' || (control.upperLimit && this.X > control.upperLimit)
|| (control.lowerLimit && this.X < control.lowerLimit)))
element.style.left = this.X + 'px';
}
if (!isNaN(this.Y)) {
if (!control || !(control.orientation != 'vertical' || (control.upperLimit && this.Y > control.upperLimit)
|| (control.lowerLimit && this.Y < control.lowerLimit)))
element.style.top = this.Y + 'px';
}
};
}
接著撰寫一個取得現在滑鼠位置的method
function absoluteCursorPosition(e) {
e = e || window.event;
if (isNaN(window.scrollX))
return new Position(e.clientX + document.documentElement.scrollLeft + document.body.scrollLeft,
e.clientY + document.documentElement.scrollTop + document.body.scrollTop);
else
return new Position(e.clientX + window.scrollX, e.clientY + window.scrollY);
}
最後重點來了,實作拖曳物件的類別
裡頭包含了紀錄之前滑鼠位置與物件起始位置的類別成員
使用dragging當指標控管拖曳行為的發生
避免因滑鼠移動到別的拖曳物件上造成預期外的行為
另提供3個使用callback function的機會,如果要設計拖曳後的行為便是利用這裡設計
稍微注意一下 dragGo 事件是綁在document上
這是要避免滑鼠移太快而讓物件自身的 onmousemove 事件沒有繼續被觸發
function dragObject(element, startCallback, moveCallback, endCallback) {
if (!element) return;
var cursorStartPos, elementClientRect, elementStartPos;
var dragging = false;
var control;
if (document.addEventListener) element.addEventListener("mousedown", dragStart, false);
else element.attachEvent("onmousedown", dragStart);
function dragStart(e) {
e = e || window.event;
if ((e.which && e.which != 1) || (e.button && e.button != 1)) return; //only allow mouse left key
if (dragging) return;
dragging = true;
if (startCallback) control = startCallback(e, element);
cursorStartPos = absoluteCursorPosition(e);
elementClientRect = element.getBoundingClientRect();
elementStartPos = new Position(elementClientRect.left - element.parentNode.scrollLeft, parseInt(element.style.top));
if (document.addEventListener) {
document.addEventListener("mousemove", dragGo, false);
document.addEventListener("mouseup", dragStop, false);
} else {
document.attachEvent("onmousemove", dragGo);
document.attachEvent("onmouseup", dragStop);
}
}
function dragGo(e) {
if (!dragging) return;
absoluteCursorPosition(e).add(elementStartPos).subtract(cursorStartPos).apply(element, control);
if (moveCallback) moveCallback(e, element);
}
function dragStop(e) {
if (!dragging) return;
dragging = false;
cursorStartPos = null;
elementStartPos = null;
if (endCallback) endCallback(e, element);
if (document.removeEventListener) {
document.removeEventListener("mousemove", dragGo, false);
document.removeEventListener("mouseup", dragStop, false);
} else {
document.detachEvent("onmousemove", dragGo);
document.detachEvent("onmouseup", dragStop);
}
}
this.dispose = function () {
if (element.removeEventListener) element.removeEventListener("mousedown", dragStart, false);
else element.detachEvent("onmousedown", dragStart);
};
}
完整程式範例請至這裡
要取消已設定可拖曳的元件的拖曳行為,可以再呼叫dispose
//after drag action is over, remove it
dothis.dispose();
實務上也常搭配 z-index 使用,請視情況自行設計
留言
張貼留言