[转帖]Mootools源码分析-40 -- Drag.Move
原帖地址:http://space.flash8.net/space/?uid-18713-action-viewspace-itemid-408713
原作者:我佛山人
代码
/*
拖放类
演示:http://demos.mootools.net/Drag.Absolutely
http://demos.mootools.net/Drag.Cart
http://demos.mootools.net/DragDrop
*/
Drag.Move = new Class({
//继承自Drag类
Extends: Drag,
options: {
//可以用于放落的对象数组
droppables: [],
//限制拖动范围的容器
container: false
},
//构造函数
initialize: function(element, options) {
//调用父类同名方法
arguments.callee.parent(element, options);
//获取可以用于放落的对象集合
this.droppables = $$(this.options.droppables);
this.container = $(this.options.container);
if (this.container && $type(this.container) != 'element') this.container = $(this.container.getDocument().body);
element = this.element;
//获取当前定位方式
var current = element.getStyle('position');
//如果为默认的静态定位,改为绝对定位
var position = (current != 'static') ? current : 'absolute';
//获取坐标
if (element.getStyle('left') == 'auto' || element.getStyle('top') == 'auto') element.position(element.getPosition(element.offsetParent));
//设置定位方式,确保可element拖动
element.setStyle('position', position);
//添加onStart事件监听,用addEvent的第三个参数指定为内部事件,可免于被移除
this.addEvent('onStart', function() {
this.checkDroppables();
}, true);
},
//开始拖动,将覆盖父类Drag的同名方法
start: function(event) {
//如果指定容器
if (this.container) {
var el = this.element, cont = this.container, ccoo = cont.getCoordinates(el.offsetParent), cps = {}, ems = {};
//取padding和margin在四个方向上的值
['top', 'right', 'bottom', 'left'].each(function(pad) {
cps[pad] = cont.getStyle('padding-' + pad).toInt();
ems[pad] = el.getStyle('margin-' + pad).toInt();
}, this);
//得到真实尺寸
var width = el.offsetWidth + ems.left + ems.right, height = el.offsetHeight + ems.top + ems.bottom;
//计算出拖动限制的上下限值
var x = [ccoo.left + cps.left, ccoo.right - cps.right - width];
var y = [ccoo.top + cps.top, ccoo.bottom - cps.bottom - height];
this.options.limit = {x: x, y: y};
}
arguments.callee.parent(event);
},
//碰撞检查,原理是检查鼠标位置是否在对象内部
checkAgainst: function(el) {
//取指定对象的坐标及尺寸值
el = el.getCoordinates();
//取当前鼠标位置
var now = this.mouse.now;
//判断鼠标是否在对象范围内
return (now.x > el.left && now.x < el.right && now.y < el.bottom && now.y > el.top);
},
//可放落检查
checkDroppables: function() {
//先根据碰撞检查过滤可放落对象数组,再取最后一个
var ōvered = this.droppables.filter(this.checkAgainst, this).getLast();
//如果当前可放落的对象不同于上次的
if (this.overed != overed) {
//如果上次可放落对象存在,触发onLeave离开事件
if (this.overed) this.fireEvent('onLeave', [this.element, this.overed]);
//如果存在当前可放落对象
if (overed) {
//更新
this.overed = overed;
//触发onEnter进入事件
this.fireEvent('onEnter', [this.element, overed]);
} else {
//置空
this.overed = null;
}
}
},
//拖动,将覆盖父类同名方法
drag: function(event) {
//调用父类同名方法
arguments.callee.parent(event);
//如果可放落对象数组不为空,在每次移动时检查碰撞
if (this.droppables.length) this.checkDroppables();
},
//停止拖动,将覆盖父类同名方法
stop: function(event) {
//在松开鼠标时再次检查碰撞
this.checkDroppables();
//触发onDrop放落事件
this.fireEvent('onDrop', [this.element, this.overed]);
//置空
this.overed = null;
//调用父类同名方法
return arguments.callee.parent(event);
}
});
//根据Drag.Move对Element的扩展实现
Element.implement({
//使对象可拖放化
makeDraggable: function(options) {
return new Drag.Move(this, options);
}
});
拖放类
演示:http://demos.mootools.net/Drag.Absolutely
http://demos.mootools.net/Drag.Cart
http://demos.mootools.net/DragDrop
*/
Drag.Move = new Class({
//继承自Drag类
Extends: Drag,
options: {
//可以用于放落的对象数组
droppables: [],
//限制拖动范围的容器
container: false
},
//构造函数
initialize: function(element, options) {
//调用父类同名方法
arguments.callee.parent(element, options);
//获取可以用于放落的对象集合
this.droppables = $$(this.options.droppables);
this.container = $(this.options.container);
if (this.container && $type(this.container) != 'element') this.container = $(this.container.getDocument().body);
element = this.element;
//获取当前定位方式
var current = element.getStyle('position');
//如果为默认的静态定位,改为绝对定位
var position = (current != 'static') ? current : 'absolute';
//获取坐标
if (element.getStyle('left') == 'auto' || element.getStyle('top') == 'auto') element.position(element.getPosition(element.offsetParent));
//设置定位方式,确保可element拖动
element.setStyle('position', position);
//添加onStart事件监听,用addEvent的第三个参数指定为内部事件,可免于被移除
this.addEvent('onStart', function() {
this.checkDroppables();
}, true);
},
//开始拖动,将覆盖父类Drag的同名方法
start: function(event) {
//如果指定容器
if (this.container) {
var el = this.element, cont = this.container, ccoo = cont.getCoordinates(el.offsetParent), cps = {}, ems = {};
//取padding和margin在四个方向上的值
['top', 'right', 'bottom', 'left'].each(function(pad) {
cps[pad] = cont.getStyle('padding-' + pad).toInt();
ems[pad] = el.getStyle('margin-' + pad).toInt();
}, this);
//得到真实尺寸
var width = el.offsetWidth + ems.left + ems.right, height = el.offsetHeight + ems.top + ems.bottom;
//计算出拖动限制的上下限值
var x = [ccoo.left + cps.left, ccoo.right - cps.right - width];
var y = [ccoo.top + cps.top, ccoo.bottom - cps.bottom - height];
this.options.limit = {x: x, y: y};
}
arguments.callee.parent(event);
},
//碰撞检查,原理是检查鼠标位置是否在对象内部
checkAgainst: function(el) {
//取指定对象的坐标及尺寸值
el = el.getCoordinates();
//取当前鼠标位置
var now = this.mouse.now;
//判断鼠标是否在对象范围内
return (now.x > el.left && now.x < el.right && now.y < el.bottom && now.y > el.top);
},
//可放落检查
checkDroppables: function() {
//先根据碰撞检查过滤可放落对象数组,再取最后一个
var ōvered = this.droppables.filter(this.checkAgainst, this).getLast();
//如果当前可放落的对象不同于上次的
if (this.overed != overed) {
//如果上次可放落对象存在,触发onLeave离开事件
if (this.overed) this.fireEvent('onLeave', [this.element, this.overed]);
//如果存在当前可放落对象
if (overed) {
//更新
this.overed = overed;
//触发onEnter进入事件
this.fireEvent('onEnter', [this.element, overed]);
} else {
//置空
this.overed = null;
}
}
},
//拖动,将覆盖父类同名方法
drag: function(event) {
//调用父类同名方法
arguments.callee.parent(event);
//如果可放落对象数组不为空,在每次移动时检查碰撞
if (this.droppables.length) this.checkDroppables();
},
//停止拖动,将覆盖父类同名方法
stop: function(event) {
//在松开鼠标时再次检查碰撞
this.checkDroppables();
//触发onDrop放落事件
this.fireEvent('onDrop', [this.element, this.overed]);
//置空
this.overed = null;
//调用父类同名方法
return arguments.callee.parent(event);
}
});
//根据Drag.Move对Element的扩展实现
Element.implement({
//使对象可拖放化
makeDraggable: function(options) {
return new Drag.Move(this, options);
}
});