Open hytzgroup opened 5 years ago
/**
* jquery easy-ui draggable
* jquery offset方法参考的原点是文档布局的原点,与是否有滚动条无关
* 1.目前元素在body中,绝对定位,目标元素的坐标是相对body的
* 2.目标元素在父容器中,父容器已经定位,目标元素的坐标也是相对body的
*/
(function(){
function drag(e){
var data = $.data(e.data.target, 'draggable');
var dragData = e.data;
// var left = scrollLeft + offsetLeft + Dx(e.pageX - e.pageX缓存)
var left = dragData.startLeft + e.pageX - dragData.startX;
var top = dragData.startTop + e.pageY - dragData.startY;
if(e.data.parent != document.body){
left += $(e.data.parent).scrollLeft();
top += $(e.data.parent).scrollTop();
}
dragData.left = left;
dragData.top = top;
}
function applyDrag(e){
var data = $.data(e.data.target, 'draggable');
var opts = data.options;
var proxy = data.proxy;
if(!proxy){
proxy = $(e.data.target);
}
proxy.css({left:e.data.left,top:e.data.top});
$('body').css('cursor',opts.cursor);
}
function onMouseDown(e){
if(!$.fn.draggable.isDragging){
return false;
}
var data = $.data(e.data.target,'dragable');
var proxy = data.proxy;
if(!proxy){
proxy = $(e.data.target);
}
proxy.css('position','absolute');
drag(e);
applyDrag(e);
options.onStartDrag.call(e.data.target,e)
return false;
}
function onMouseMove(e){
if(!$.fn.draggable.isDragging){
return false;
}
var data = $.data(e.data.target, 'draggable');
drag(e);
if(data.options.onDrag.call(e.data.target, e) != false){
applyDrag(e);
}
return false;
}
function onMouseUp(e){
if(!$.fn.draggable.isDragging){
clearTimer();
return false;
}
onMouseMove(e);
var data = $.data(e.data.target, 'draggable');
var opts = data.options;
opts.onEndDrag.call(e.data.target, e);
$(e.data.target).css({
position: e.data.startPosition,
left: e.data.left,
top: e.data.top
})
clearTimer();
return false;
}
function clearTimer(){
if($.fn.draggable.timer){
clearTimeout($.fn.draggable.timer);
$.fn.draggable.timer = undefined;
}
$(document).unbind('.draggable');
$.fn.draggable.isDragging = false;
setTimeout(function(){
$('body').css('cursor', '')
}, 100);
}
$.fn.draggable = function(options,param){
if(typeof options == 'string'){
return $.fn.draggable.methods[options](this,param)
}
return this.each(function(){
var opts;
var state = $.data(this, 'draggable');
if(state){
state.handle.unbind('.draggable');
opts = $.extend(state.options, options);
}else{
opts = $.extend({},$.fn.draggable.defaults, options || {});
}
if(opts.disabled == true){
$(this).css('cursor', 'default');
return;
}
// 被拖拽的对象
var handle = null;
if(opts.handle == null){
handle = $(this);
}else{
handle = typeof opts.handle == 'string'
? $(opts.handle, this)
: handle;
}
$.data(this, 'draggable', {
options: opts,
handle: handle
})
if(opts.disabled){
$(this).css('cursor', '');
return;
}
handle.unbind('.draggable')
.bind('mousemove.draggable',{target: this},function(e){
if($.fn.draggable.isDragging){
return;
}
var options = $.data(e.data.target, 'draggable').options;
// 鼠标的位置在handler的内部
if(checkArea(e)){
$(this).css('cursor', options.cursor);
}else{
$(this).css('cursor','');
}
})
.bind('mouseleave.draggable',{target: this},function(e){
$(this).css('cursor', '');
})
.bind('mousedown.draggable',{target: this},function(e){
// 是否在元素内部
if(checkArea(e) == false){
return;
}
$(this).css('cursor','');
// handler相对于父元素的偏移
var position = $(e.data.target).position();
// handler相对于文档视口的偏移(不受滚动条的影响)
var offset = $(e.data.target).offset();
var data = {
startPosition: $(e.data.target).css('position'), // hanlder的原始positon属性
startLeft: position.left,
startTop: position.top,
left: position.left,
top: position.top,
startX: e.pageX, // 鼠标相对于文档视口的偏移
startY: e.pageY,
width: $(e.data.target).outerWidth(),
height: $(e.data.target).outerHeight(),
offsetWidth: e.pageX - offset.left,
offsetHeight: e.pageY = offset.top,
target: e.data.target,
parent: $(e.data.target).parent()[0]
}
$.extend(e.data,data);
var options = $.data(e.data.target, 'draggable').options;
if(options.onBeforeDrag.call(e.data.target,e) == false){
return;
}
// 给document绑定mousedown、mousemove、mouseup
// 按住鼠标不送手,会触发mousemove、mouseup
$(document).bind('mousedown.draggable', e.data, onMouseDown);
$(document).bind('mousemove.draggable', e.data, onMouseMove);
$(document).bind('mouseup.draggable', e.data, onMouseUp);
// 手动触发mousedown的回调函数
$.fn.draggable.timer = setTimeout(function(){
$.fn.draggable.isDragging = true;
onMouseDown(e);
},options.delay);
return false;
})
function checkArea(e){
// 布局视口的作为原点
var opts = $.data(e.data.target, 'draggable');
var handle = opts.handle;
var offset = $(handle).offset();
var outerWidth = $(handle).outerWidth();
var outerHeight = $(handle).outerHeight();
var top = e.pageY - offset.top;
var right = offset.left + outerWidth - e.pageX;
var bottom = offset.top + outerHeight - e.pageY;
var left = e.pageX - offset.left;
return Math.min(top, right, bottom, left) > opts.options.edge;
}
})
}
$.fn.draggable.methods = {
options: function(jq){
return $.data(jq[0], 'draggable').options;
},
proxy: function(jq){
return $.data(jq[0], 'draggable').proxy;
},
enable: function(jq){
return jq.each(function(){
$(this).draggable({disabled:false})
})
},
disable: function(){
return jq.each(function(){
$(this).draggable({disabled:true})
})
}
};
$.fn.draggable.defaults = {
proxy: null,
revert: false,
cursor: 'move',
deltaX: null,
deltaY: null,
handle: null,
disabled: false,
edge: 0,
axis: null,
delay: 100,
onBeforeDrag: function(e){},
onStartDrag: function(e){},
onDrag: function(e){},
onEndDrag: function(e){},
onStopDrag: function(){}
};
$.fn.draggable.isDragging = false;
})(jQuery)
拖拽原理
综述
拖拽是前端的一个基本技能,拖拽涉及到前端的许多基础知识,比如:元素的尺寸、偏移量计算、scroll、事件绑定等。并且拖拽是前端组件的一个基础功能。本文旨在学习拖拽的基本原理。
基本原理
给被拖拽元素添加mousedown事件,记录鼠标距离布局视口的坐标event.pageX、event.pageY。获取被拖拽元素的距离布局视口的offsetTop、offsetLeft。计算鼠标的点击点距离被拖拽元素的左上角的偏移量dx、dy。
在mousedown事件内部,给document对象添加mousemove事件。记录鼠标距离布局视口的坐标,计算元素的left、top值。
在mousedown事件回调函数内,document对象添加mouseup事件。移除在document对象上注册的mousemove和mouseup事件
实例一
实例二
从实例中可以得出以下结论: