1、我們常常會通過修改元素的top,left,translate來其的位置發生改變。修改元素的left,top值,但會引起頁面重繪,而transform不會,所以要優先使用transform。
2、如何獲取當前瀏覽器支持的transform兼容寫法
3、獲取元素的初始位置:
4、需要綁定的事件:mousedown,mousemove,mouseup
而在移動端,分別與之對應的則是touchstart、touchmove、touchend。
5、原理
當事件觸發時,我們可以通過事件對象獲取到鼠標的精切位置。這是實現拖拽的關鍵。當鼠標按下(mousedown觸發)時,我們需要記住鼠標的初始位置與目標元素的初始位置,我們的目標就是實現當鼠標移動時,目標元素也跟着移動,根據常理我們可以得出如下關係:
移動後的鼠標位置 - 鼠標初始位置 = 移動後的目標元素位置 - 目標元素的初始位置
如果鼠標位置的差值我們用dis來表示,那麼目標元素的位置就等於:
移動後目標元素的位置 = dis + 目標元素的初始位置通過事件對象,我們可以精確的知道鼠標的當前位置,因此當鼠標拖動(mousemove)時,我們可以不停的計算出鼠標移動的差值,以此來求出目標元素的當前位置。這個過程,就實現了拖拽。
而在鼠標鬆開(mouseup)結束拖拽時,我們需要處理一些收尾工作。
6、封裝原則
如何合理的處理屬性與方法的位置。
構造函數中: 屬性與方法爲當前實例單獨擁有,只能被當前實例訪問,並且每聲明一個實例,其中的方法都會被重新創建一次。
原型中: 屬性與方法爲所有實例共同擁有,可以被所有實例訪問,新聲明實例不會重複創建方法。
模塊作用域中:屬性和方法不能被任何實例訪問,但是能被內部方法訪問,新聲明的實例,不會重複創建相同的方法。
對於方法的判斷比較簡單。
因爲在構造函數中的方法總會在聲明一個新的實例時被重複創建,因此我們聲明的方法都儘量避免出現在構造函數中。
而如果你的方法中需要用到構造函數中的變量,或者想要公開,那就需要放在原型中。
如果方法需要私有不被外界訪問,那麼就放置在模塊作用域中。
對於屬性的判斷
對於屬性放置於什麼位置需要在實際開發中不斷的總結經驗。
如果屬性值只能被實例單獨擁有,比如person對象的name,只能屬於某一個person實例,又比如這裏拖拽對象中,某一個元素的初始位置,也僅僅只是這個元素的當前位置,這個屬性,則適合放在構造函數中。
而如果一個屬性僅僅供內部方法訪問,這個屬性就適合放在模塊作用域中。
模塊封裝代碼:
; //文件合併時,防止前一個文件末尾沒加分號
(function() {
//私有屬性,內部使用,不需實例訪問
var transform = getTransform();
function Drag(selector) {
this.elem = typeof selector == 'object' ? selector : document.getElementById(selector);
this.startX = 0;
this.startY = 0;
this.sourceX = 0;
this.sourceY = 0;
this.init();
}
Drag.prototype = {
constructor: Drag,
init: function() {
this.setDrag();
},
getStyle: function(property) {
return window.getComputedStyle ? window.getComputedStyle(this.elem, null).getPropertyValue(property) : this.currentStyle.getAttribute(property);
},
//獲取當前元素的位置信息,注意與之前的不同之處
getPosition: function() {
var pos = { x: 0, y: 0 };
if (transform) {
var transformValue = this.getStyle(transform);
if (transformValue == 'none') {
this.elem.style[transform] = 'translate(0,0)';
} else {
var temp = transformValue.match(/-?\d+/g);
pos = {
x: parseInt(temp[4].trim()),
y: parseInt(temp[5].trim())
}
}
} else {
if (this.getStyle('position') == 'static') {
this.elem.style.position = 'relative';
} else {
pos = {
x: parseInt(this.getStyle('left') ? this.getStyle('left') : 0),
y: parseInt(this.getStyle('top') ? this.getStyle('top') : 0)
}
}
}
return pos;
},
// 用來設置當前元素的位置
setPosition: function(pos) {
if (transform) {
this.elem.style[transform] = 'translate(' + pos.x + 'px, ' + pos.y + 'px)';
} else {
this.elem.style.left = pos.x + 'px';
this.elem.style.top = pos.y + 'px';
}
},
setDrag: function() {
var self = this;
this.elem.addEventListener('mousedown', start, false);
function start(event) {
//鼠標初始位置
self.startX = event.pageX;
self.startY = event.pageY;
var pos = self.getPosition();
self.sourceX = pos.x;
self.sourceY = pos.y;
document.addEventListener('mousemove', move, false);
document.addEventListener('mouseup', end, false);
}
function move(event) {
// 獲取鼠標當前位置
var curX = event.pageX;
var curY = event.pageY;
// 計算差值
var disX = curX - self.startX;
var disY = curY - self.startY;
self.setPosition({
x: (self.sourceX + disX).toFixed(),
y: (self.sourceY + disY).toFixed()
});
}
function end(event) {
document.removeEventListener('mousemove', move);
document.removeEventListener('mouseup', end);
//do other things
}
}
}
//私有方法
function getTransform() {
var transform = '',
divStyle = document.createElement('div').style,
transformArr = ['transform', 'webkitTransform', 'MozTransform', 'msTransform', 'oTransform'];
//通過循環找出瀏覽器識別的那個,in操作符用於判斷是否識別
for (var i = 0, len = transformArr.length; i < len; i++) {
if (transformArr[i] in divStyle) {
return transform = transformArr[i];
}
}
return transform;
}
window.Drag = Drag;
})();
new Drag('target');
new Drag('target2');
html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
* {
padding: 0;
margin: 0;
}
#target,
#target2 {
width: 50px;
height: 50px;
background-color: orange;
cursor: move;
}
#target2 {
background-color: red;
}
</style>
</head>
<body>
<div style="height:1000px">hha</div>
<div id="target"></div>
<div id="target2"></div>
</body>
</html>
jquery實例方法擴展:
// 通過擴展方法將拖拽擴展爲jQuery的一個實例方法
(function ($) {
$.fn.extend({
becomeDrag: function () {
new Drag(this[0]);
return this; // 注意:爲了保證jQuery所有的方法都能夠鏈式訪問,每一個方法的最後都需要返回this,即返回jQuery實例
}
})
})(jQuery);
參考鏈接:http://www.jianshu.com/p/b3dee0e84454
http://www.jianshu.com/p/3f97570d22b4