技术分享
拖拽原理及组件封装
— 刘佳
— 刘佳
鼠标按下 -> 鼠标移动(随鼠标移动) -> 鼠标抬起
oDiv.onmousedown = function(){ ...//鼠标按下 oDiv.onmousemove = function(){ ...//鼠标移动 }; oDiv.onmouseup = function(){ ...//鼠标抬起 }; };
按N显示代码
按N显示代码
var oDiv = document.getElementById('div1');
oDiv.onmousedown = function(ev) {
var ev = ev || event;
// 1、Event 对象代表事件的状态
// 2、ie6\7\8下获取不到ev
var disX = ev.clientX - this.offsetLeft;
var disY = ev.clientY - this.offsetTop;
// 获取鼠标点击时在div中的相对位置
if (oDiv.setCapture) {oDiv.setCapture();}
// 文字选中bug:ie下,设置全局捕获
document.onmousemove = function(ev) {
var ev = ev || event;
oDiv.style.left = ev.clientX - disX + 'px';
oDiv.style.top = ev.clientY - disY + 'px';
};
document.onmouseup = function() {
document.onmousemove = null;
// 获取当前鼠标位置,
// 减去与div的相对位置得到当前div应该被拖拽的位置
if (oDiv.releaseCapture) {oDiv.releaseCapture();}
// 文字选中bug:ie下,释放全局捕获
};
return false;
// 文字选中bug:标准下,阻止事件默认行为
};
限制范围的拖拽
磁性吸附(边缘吸附、自动吸入)
拖拽排序
封装成函数
按N显示代码
距离磁性边缘一定距离时,自动拉到吸附位置
边缘吸附 VS 自动吸入
按N显示代码
按N显示代码
步骤原理:
▶ 点击节点将其绝对定位脱离文档流
▶ 在其原位置插入一空白元素占位
▶ visibility: hidden;
▶ 根据节点被拖拽的位置,计算其重新排序后的顺序
▶ 将占位空白元素插入到新位置
▶ mouseUp时将节点插入空白元素的位置,将其替换
按N显示代码
面向对象的思想 OOP
组件封装方法
// 构造函数================================================
var Drag = function(opt){
this.obj = null; // this:Drag对象,this.obj:元素
this.disX = 0;
this.disY = 0;
this.settings = { //默认参数
toDown : function(){},
toMove : function(){},
toUp : function(){}
};
// 如果创建对象的时候就传入了配置参数,执行init()
opt && this.init(opt);
};
// 方法================================================
Drag.prototype = {
// init() 初始化
init: function(opt) {
if (!opt) { return false;}
var This = this; // 保存this
// 判断传入的是对象还是id名,获取对象
this.obj = 'string'==(typeof opt.id) ? document.getElementById(opt.id) : opt.id;
// 调用extend() 将配置的参数传到对象中保存
this.extend( this.settings , opt );
this.obj.onmousedown = function(ev){
var ev = ev || window.event;
// 执行fnDown()
This.fnDown(ev);
if (oDiv.setCapture) {oDiv.setCapture();}
document.onmousemove = function(ev){
var ev = ev || window.event;
// 执行fnDown()
This.fnMove(ev);
};
document.onmouseup = function(){
// 执行fnUp()
This.fnUp();
if (oDiv.releaseCapture) {oDiv.releaseCapture();}
};
return false;
};
},
// fnDown() 鼠标按下方法
fnDown: function(ev) {
this.obj.style.zIndex = this.setZ(); // 设置层级
this.disX = ev.clientX - this.obj.offsetLeft;
this.disY = ev.clientY - this.obj.offsetTop;
this.settings.toDown(this.obj); // 执行自定义的toDown()
},
// fnMove() 鼠标移动方法
fnMove: function(ev) {
this.obj.style.left = ev.clientX - this.disX + 'px';
this.obj.style.top = ev.clientY - this.disY + 'px';
this.settings.toMove(this.obj); // 执行自定义的toMove()
},
// fnUp() 鼠标抬起方法
fnUp: function() {
document.onmousemove = null;
document.onmouseup = null;
this.settings.toUp(this.obj); // 执行自定义的toUp()
},
// extend() 传参
extend: function(obj1,obj2) {
for(var attr in obj2){
obj1[attr] = obj2[attr];
}
},
// setZ() 其他div层级
setZ: function(){
var otherDiv = this.obj.parentNode.getElementsByTagName('div');
var n = 0;
for(var i=0; i < otherDiv.length; i++){
var dn = parseInt(otherDiv[i].style.zIndex);
n = ( dn > n ? dn : n ); // if ( dn > n) { n = dn;}
}
return n+1;
}
}
// 调用================================================
var aDiv = document.getElementsByTagName('div');
var d1 = new Drag({ // div1
id : aDiv[0], // 传入对象
toDown : function(obj){
obj.style.opacity = '0.6';
obj.innerHTML = parseInt(obj.innerHTML) +1;
},
toUp : function(obj){
obj.style.opacity = '1';
}
});
var d2 = new Drag({ // div2
id : 'div2', // 直接穿入对象id
toDown : function(obj){
obj.style.backgroundColor = '#E03E5D';
obj.style.opacity = '0.6';
obj.innerHTML = parseInt(obj.innerHTML) -1;
},
toUp : function(obj){
obj.style.opacity = '1';
}
});
var d3 = new Drag({ // div3
id : aDiv[2],
toDown : function(obj){
obj.style.backgroundColor = '#333';
obj.style.opacity = '0.6';
obj.innerHTML = '我是黑色';
obj.style.fontSize = '20px';
},
toUp : function(obj){
obj.innerHTML = '';
obj.style.opacity = '1';
}
});
var d4 = new Drag({ // div4
id : aDiv[3],
toDown : function(obj){
obj.style.backgroundColor = '#3E96E0';
obj.style.opacity = '0.8';
obj.innerHTML = '我是方形';
obj.style.fontSize = '20px';
obj.style.borderRadius = '0';
},
toMove : function(obj){
document.body.style.background = '#333';
},
toUp : function(obj){
obj.innerHTML = '';
obj.style.opacity = '1';
}
});
// 构造函数================================================
var Drag = function(opt){
this.obj = null; // this:Drag对象,this.obj:元素
this.disX = 0;
this.disY = 0;
this.rangeId = null; // 范围
this.hasRange = false;
this.rangeJson = {};
this.settings = { //默认参数
toDown : function(){},
toMove : function(){},
toUp : function(){}
};
opt && this.init(opt);
};
// 方法================================================
Drag.prototype = {
init: function(opt) {
if (!opt) { return false;}
// 处理obj指向
this.obj = 'string'==(typeof opt.id) ? document.getElementById(opt.id) : opt.id;
if (opt.rangeId){ // 处理range
this.rangeId = ('string'==(typeof opt.rangeId) ? document.getElementById(opt.rangeId) : opt.rangeId) ;
this.hasRange = true;
this.rangeJson = this.setRange();
this.obj.style.left = this.rangeJson.left + 'px';
this.obj.style.top = this.rangeJson.top + 'px';
}
this.extend( this.settings , opt );
this.run();
},
run: function(){
var This = this;
this.obj.onmousedown = function(ev){
This.fnDown( ev||window.event );
document.onmousemove = function(ev){ This.fnMove( ev||window.event ); };
document.onmouseup = function(){ This.fnUp(); };
return false;
};
},
fnDown: function(ev) {
this.obj.style.zIndex = this.setZindex(); // 设置层级
this.disX = ev.clientX - this.obj.offsetLeft;
this.disY = ev.clientY - this.obj.offsetTop;
if (this.setCapture) {this.setCapture();}
this.settings.toDown(this.obj); // toDown()
},
fnMove: function(ev) {
var L = ev.clientX - this.disX;
var T = ev.clientY - this.disY;
if (this.rangeJson) { // 判断范围
if ( L < this.rangeJson.left) { L = this.rangeJson.left; }
else if (L > this.rangeJson.right) { L = this.rangeJson.right; }
if ( T < this.rangeJson.top ) { T = this.rangeJson.top; }
else if ( T > this.rangeJson.bottom) { T = this.rangeJson.bottom; }
}
this.obj.style.left = L + 'px';
this.obj.style.top = T + 'px';
this.settings.toMove(this.obj); // toMove()
},
fnUp: function() {
document.onmousemove = null;
document.onmouseup = null;
this.settings.toUp(this.obj); // toUp()
if (this.releaseCapture) {this.releaseCapture();}
},
extend: function(obj1,obj2) {
for(var attr in obj2){ obj1[attr] = obj2[attr]; }
},
setZindex: function(){
var otherDiv = this.obj.parentNode.getElementsByTagName('div');
var n = 0;
for(var i=0; i n ? dn : n );
}
return n+1;
},
setRange: function(){
return {
left : this.posLeft(this.rangeId),
right : this.posLeft(this.rangeId) + this.rangeId.offsetWidth - this.obj.offsetWidth,
top : this.posTop(this.rangeId),
bottom : this.posTop(this.rangeId) + this.rangeId.offsetHeight - this.obj.offsetHeight
};
},
posLeft: function (obj){ // 获取绝对位置left
var iLeft = 0;
while(obj){
iLeft += obj.offsetLeft;
obj = obj.offsetParent;
if(obj && obj!=document.body && obj!=document.documentElement){
iLeft += this.getStyle(obj, 'borderLeftWidth');
}
}
return iLeft;
},
posTop: function (obj){ // 获取绝对位置top
var iTop = 0;
while(obj){
iTop += obj.offsetTop;
obj = obj.offsetParent;
if(obj && obj!=document.body && obj!=document.documentElement){
iTop += this.getStyle(obj, 'borderTopWidth');
}
}
return iTop;
},
getStyle: function (obj,attr){
if(obj.currentStyle){
return parseFloat( obj.currentStyle[attr]) || 0;
}
return parseFloat( getComputedStyle(obj)[attr]) || 0;
}
}
// 调用================================================
window.onload = function(){
// div1
var d1 = new Drag({
id : 'div1', // 传入对象
toDown : function(obj){
obj.style.opacity = '0.6';
obj.innerHTML = parseInt(obj.innerHTML) +1;
},
toUp : function(obj){
obj.style.opacity = '1';
}
});
// div2
var d2= new Drag({
id : 'div2', // 传入对象
rangeId : 'box', // 限制范围填写id,否则不用填
toDown : function(obj){
obj.style.opacity = '0.6';
},
toUp : function(obj){
obj.style.opacity = '1';
}
});
};